MetaList 0.13.0__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metalist-0.13.0/metalist.egg-info → metalist-0.14.0}/PKG-INFO +11 -1
- {metalist-0.13.0 → metalist-0.14.0}/README.md +9 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/middleware/auth.py +1 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/auth.py +6 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/notes.py +25 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/config.py +0 -1
- {metalist-0.13.0 → metalist-0.14.0}/app/encryption_audit.py +16 -9
- {metalist-0.13.0 → metalist-0.14.0}/app/exception_boundaries.py +8 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/main.py +5 -3
- metalist-0.14.0/app/presentation/login_page.py +18 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-dictation.md +2 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-formatting.md +6 -3
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-menus.md +1 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-privacy.md +8 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-references.md +1 -1
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-releases.md +9 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-search.md +9 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/backlink_index.py +1 -1
- {metalist-0.13.0 → metalist-0.14.0}/app/services/content_formatting.py +11 -5
- {metalist-0.13.0 → metalist-0.14.0}/app/services/embedded_references.py +15 -59
- metalist-0.14.0/app/services/link_title_retry.py +169 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/link_titles.py +389 -5
- {metalist-0.13.0 → metalist-0.14.0}/app/services/note_store.py +15 -6
- {metalist-0.13.0 → metalist-0.14.0}/app/services/reference_presentation.py +1 -1
- {metalist-0.13.0 → metalist-0.14.0}/app/services/search_index.py +67 -12
- {metalist-0.13.0 → metalist-0.14.0}/app/services/search_text.py +44 -3
- {metalist-0.13.0 → metalist-0.14.0}/app/services/tab_state.py +20 -6
- metalist-0.14.0/app/startup_console.py +100 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/config/agent-menu-actions.json +6 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/config/command_palette_tags.json +4 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/css/main.css +247 -183
- metalist-0.14.0/app/static/js/locked.js +36 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/main.js +0 -1
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +4 -2
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/api-client.js +13 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/auth.js +162 -284
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/command-palette-controller.js +18 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/endpoint-registry.js +8 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/preferences-store.js +38 -23
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/config.js +2 -10
- metalist-0.14.0/app/static/js/modules/modals/link-title-retry-modal.js +308 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/dictation-paste-service.js +9 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +9 -1
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-syntax-service.js +52 -0
- metalist-0.14.0/app/templates/_logo_mark.html +6 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/templates/base.html +0 -5
- {metalist-0.13.0 → metalist-0.14.0}/app/templates/index.html +37 -51
- metalist-0.14.0/app/templates/locked.html +37 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/utils/text_utils.py +42 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/version.py +1 -1
- {metalist-0.13.0 → metalist-0.14.0}/main.py +57 -25
- {metalist-0.13.0 → metalist-0.14.0/metalist.egg-info}/PKG-INFO +11 -1
- {metalist-0.13.0 → metalist-0.14.0}/metalist.egg-info/SOURCES.txt +5 -1
- {metalist-0.13.0 → metalist-0.14.0}/metalist.egg-info/requires.txt +1 -0
- {metalist-0.13.0 → metalist-0.14.0}/pyproject.toml +1 -0
- metalist-0.13.0/app/static/js/locked.js +0 -14
- metalist-0.13.0/app/static/video/login-startup.mp4 +0 -0
- metalist-0.13.0/app/templates/locked.html +0 -85
- {metalist-0.13.0 → metalist-0.14.0}/MANIFEST.in +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/deps.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/dev.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/note_requests.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/request_auth.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/ai.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/app_updates.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/backups.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/files.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/ontology.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/reminders.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/remote_images.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/routes/test.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/transactions.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/api/upload_limits.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/data_directory.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/editable_files_migration.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/engine.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/file_schema.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/file_session.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/files_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/link_titles_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/live_recovery.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/migrations.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/notes_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/reminders_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/retire_sounds.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/schema.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/search_history_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/session.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/settings_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/tab_state_sql.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/db/version.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/https_proxy.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/commands.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/database.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/entities.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/enums.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/linked_list.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/list_operations.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/list_traversal.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/note_crud.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/models/utils.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/network_settings.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/presentation/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/presentation/render/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/presentation/templates.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/authenticated_logging.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/encryption.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/http_error_diagnostics.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/http_headers.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/note_html.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/request_boundary.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/request_hosts.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/sensitive_cache.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/sensitive_logging.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/shell_execution.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/security/validation_errors.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/server_runtime.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/action_log.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/agent_loop.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/agent_tools.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/citation_tokens.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/cloud_privacy.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/context.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/evidence_serialization.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/execution_errors.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/failure_explanations.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/help_catalog.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/history.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/inference.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/investigation.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/judging.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/menu_actions.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/model_policy.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/note_aliases.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/openai_cost_tracking.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/openai_inference.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/prompt_settings.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/prompts/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/prompts/agent.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/prompts/final-response.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/prompts/system.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/release_notes.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/retrieval_settings.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/runtime.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/scope.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skill_settings.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-ai.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-data.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-notes.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-reminders.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/help-tags.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/staged-summary.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/tag-proposals.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/skills/web-browsing.md +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/staged_summary.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/structured_inference.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/tagging.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/tagging_run.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/token_estimation.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/tool_calling.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/trace.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/web_actions.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/web_capabilities.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/web_evidence.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/web_fetch.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/agent/web_settings.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/ai_chat.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/ai_chat_rendering.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/ai_chat_stream.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/app_update_worker.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/app_updates.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/auth.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/auth_cache_state.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/auth_service.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/backlinks.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/backup_service.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/backup_settings_service.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/bulk_operation.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/client_state_service.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/content_cache.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/diagnostics.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/dictation_cleanup.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/encryption.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/exception_capture.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/file_edit_sessions.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/file_registry.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/file_storage.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/file_text_preview.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/footnote_layout.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/footnote_rendering.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/hierarchy.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/html_export.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/html_unformatting.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/hydration_state.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/image_size_formatting.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/inline_image_dimensions.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/inline_image_occurrences.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/input_errors.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/integrity.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/latex_rendering.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/login_rate_limit.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/maintenance_mode.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/markdown_rendering.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/namespace_deletion_worker.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/namespace_rename_worker.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/namespace_runtime_guard.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/namespace_switcher.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/note_fullscreen.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/note_image_tags.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/note_ordering.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/ontology_rules_store.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/openai_credentials.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/password_note_fields.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/public_http.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/reminders.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/remote_image_proxy.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/request_recovery.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/resource_limits.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/root_sorting.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/runtime_generation.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/runtime_hardening.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/runtime_lock.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/search_history.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/search_history_storage.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/search_query.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/selected_text_tag.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/self_update.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/session_timeout_service.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/shell_session_service.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/snapshot.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/store.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/structured_note_renderers.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/sync.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/sync_state.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/tag_case.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/tag_ontology.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/tag_rename.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/tag_suggestions.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/tag_term_matching.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/test_reset.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/tokens.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/undo_state.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/update_backups.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/update_installer.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/update_preflight.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/view_cache.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/view_diff.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/view_state.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/services/windows_process_control.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/startup_environment.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/startup_js_sanity.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/startup_sanity.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/startup_sanity_config.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/css/floating-notes.css +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/css/forms.css +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/img/favicon.ico +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/agent-web-settings.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-message-placement.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/bulk-scope-question.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/confirmation-card.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/confirmation-question.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/summary-batch-preview.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/api-error-diagnostics.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/api-failure-classification-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/app-update-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/application-state.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/connectivity-monitor.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/dom-utils-fixed.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/elapsed-time.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-autosave.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-editor-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-editor-state.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-loader.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-preview-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-scene.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/expected-errors.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/login-namespace-picker.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/maintenance.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/ai-agent-settings-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-result-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/base-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/confirmation-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/dictation-settings-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/help-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-modals.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/ontology-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/password-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/version-info-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/modals/visual-cues-modal.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/context-menu-events.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/keyboard-events.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/mouse-events.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/mode-context.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/dictation-note-paste.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/dictation-paste-padding.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/dropped-file-preview-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-drag-indicator-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-note-creation-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/viewport-hold-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/note-html-sanitizer.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/password-operation-response.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/password-policy.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/password-strength.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/selection-markers.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/namespace-deleted.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/namespace-renamed.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/dompurify-3.4.16.LICENSE.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/dompurify-3.4.16.min.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/excalidraw.css +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Bold.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Medium.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Regular.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Virgil/Virgil-Regular.woff2 +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1.LICENSE.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1.min.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/markdown-it-14.3.2.LICENSE.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/markdown-it-14.3.2.min.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/static/note-html-policy.json +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/templates/maintenance.html +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/templates/namespace_deleted.html +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/templates/namespace_renamed.html +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/templates/notes_list.html +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/upload_limits.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/add_selected_text_tag.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/base.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/bulk_tag_proposals.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/collapse.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/copy_note.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/create_child.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/create_file_preview_child.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/create_note.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/create_sibling.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/delete_tag.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/expand.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/file_edit_session.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/indent.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/lock.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/move.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/move_to_top.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/outdent.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/paste_child.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/prefetch_link_titles.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/prioritize.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/redo.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/rename_tag.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/resize_image.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/run_shell.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/search_context_tags.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/split_note.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/tag_proposals.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/toggle_reference_mode.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/undo.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/unformat_content.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/update_content.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/usecases/view.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/utils/__init__.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/app/utils/encryption.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/convert-from-legacy.py +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.13.0 → metalist-0.14.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metalist
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
|
|
5
5
|
Project-URL: Homepage, https://github.com/evolvingstuff/metalist
|
|
6
6
|
Project-URL: Repository, https://github.com/evolvingstuff/metalist
|
|
@@ -23,6 +23,7 @@ Requires-Dist: pydantic==2.13.4
|
|
|
23
23
|
Requires-Dist: pypdf==6.19.0
|
|
24
24
|
Requires-Dist: python-dotenv==1.2.2
|
|
25
25
|
Requires-Dist: python-multipart==0.0.32
|
|
26
|
+
Requires-Dist: rich==14.3.4
|
|
26
27
|
Requires-Dist: starlette==1.3.1
|
|
27
28
|
Requires-Dist: tqdm==4.70.0
|
|
28
29
|
Requires-Dist: tree-sitter==0.25.2
|
|
@@ -49,6 +50,15 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
49
50
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
50
51
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
51
52
|
|
|
53
|
+
## Changes in 0.14.0
|
|
54
|
+
|
|
55
|
+
- A new login screen: one dark screen with the MetaList logo. The namespace, password and OK fade in together; once the password is accepted, the loading progress slides in with the current step and the seconds elapsed. When the first login after an update backs up and upgrades the namespace, a note under OK says so. The Session locked page has the same look, and there is no white flash between them.
|
|
56
|
+
- Web link titles: links to Reddit (including share links), YouTube, Vimeo, TikTok, Spotify and SoundCloud get their real titles. Lookups are paced per site, so a note full of links no longer trips a site's rate limit. Login, consent and site-name-only titles ("Sign in", "Reddit") show the link instead. The new command palette action Retry failed link titles asks every failed link again, with a progress dialog.
|
|
57
|
+
- Quoted search also matches link titles and the URLs hidden behind link labels, and the AI sees those URLs too. Pasting into a quoted search inserts the text as copied.
|
|
58
|
+
- `[[note id]]` is always a link, even in a note with a `[[ ]]` formatting tag.
|
|
59
|
+
- The startup output in the terminal is easier to read: the version, a check mark per check, and each namespace's URLs lined up.
|
|
60
|
+
- Fixed: clicking the AI chat's $ or eye button twice quickly crashed with "Redundant state change".
|
|
61
|
+
|
|
52
62
|
## Changes in 0.13.0
|
|
53
63
|
|
|
54
64
|
- Dictation: text from speech-to-text tools such as Superwhisper, pasted into the search bar or any tag field, becomes your existing tags ("neural network" gives `neural-network`). Say "quote … end quote" for text, "minus" to exclude, "at" before meta tags such as `@todo`. In a note, the words after "start tags" go to its tag bar. The phrases are set in Dictation Settings, and one undo restores what was pasted.
|
|
@@ -12,6 +12,15 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
12
12
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
13
13
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
14
14
|
|
|
15
|
+
## Changes in 0.14.0
|
|
16
|
+
|
|
17
|
+
- A new login screen: one dark screen with the MetaList logo. The namespace, password and OK fade in together; once the password is accepted, the loading progress slides in with the current step and the seconds elapsed. When the first login after an update backs up and upgrades the namespace, a note under OK says so. The Session locked page has the same look, and there is no white flash between them.
|
|
18
|
+
- Web link titles: links to Reddit (including share links), YouTube, Vimeo, TikTok, Spotify and SoundCloud get their real titles. Lookups are paced per site, so a note full of links no longer trips a site's rate limit. Login, consent and site-name-only titles ("Sign in", "Reddit") show the link instead. The new command palette action Retry failed link titles asks every failed link again, with a progress dialog.
|
|
19
|
+
- Quoted search also matches link titles and the URLs hidden behind link labels, and the AI sees those URLs too. Pasting into a quoted search inserts the text as copied.
|
|
20
|
+
- `[[note id]]` is always a link, even in a note with a `[[ ]]` formatting tag.
|
|
21
|
+
- The startup output in the terminal is easier to read: the version, a check mark per check, and each namespace's URLs lined up.
|
|
22
|
+
- Fixed: clicking the AI chat's $ or eye button twice quickly crashed with "Redundant state change".
|
|
23
|
+
|
|
15
24
|
## Changes in 0.13.0
|
|
16
25
|
|
|
17
26
|
- Dictation: text from speech-to-text tools such as Superwhisper, pasted into the search bar or any tag field, becomes your existing tags ("neural network" gives `neural-network`). Say "quote … end quote" for text, "minus" to exclude, "at" before meta tags such as `@todo`. In a note, the words after "start tags" go to its tag bar. The phrases are set in Dictation Settings, and one undo restores what was pasted.
|
|
@@ -41,6 +41,7 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
41
41
|
NO_TOKEN_REFRESH_PATHS = [
|
|
42
42
|
f"{API_PREFIX}/auth/status", # Polling service pings this for connectivity
|
|
43
43
|
f"{API_PREFIX}/reminders/evaluate", # Reminder polling is not user-initiated activity
|
|
44
|
+
f"{API_PREFIX}/notes/link-titles/retry", # The retry dialog polls its progress
|
|
44
45
|
]
|
|
45
46
|
|
|
46
47
|
# Note: /api/notes/* paths are NOT in this list - they require auth when password is set
|
|
@@ -97,6 +97,7 @@ from app.services.client_state_service import save_client_preferences
|
|
|
97
97
|
from app.services.client_state_service import save_command_palette_usage
|
|
98
98
|
from app.services.openai_credentials import openai_credential_store
|
|
99
99
|
from app.services.input_errors import NamespaceInputRejected
|
|
100
|
+
from app.services.link_title_retry import stop_link_title_retry
|
|
100
101
|
|
|
101
102
|
|
|
102
103
|
router = APIRouter(prefix="/auth", tags=["auth2"])
|
|
@@ -595,6 +596,9 @@ def logout(
|
|
|
595
596
|
openai_credential_store.clear_session(session_key=session_key)
|
|
596
597
|
token_service.revoke_token(token)
|
|
597
598
|
shell_session_service.reset()
|
|
599
|
+
# Lock and login end a retry through the runtime generation; a passwordless
|
|
600
|
+
# logout does not change it, so stop the retry here.
|
|
601
|
+
stop_link_title_retry()
|
|
598
602
|
view_cache.clear()
|
|
599
603
|
reset_all_undo_state()
|
|
600
604
|
reset_sync_state()
|
|
@@ -712,6 +716,8 @@ def auth_status(
|
|
|
712
716
|
return {
|
|
713
717
|
"version": VERSION,
|
|
714
718
|
"database_user_version": database_user_version,
|
|
719
|
+
# The next login backs up and upgrades this database (the login screen says so).
|
|
720
|
+
"database_upgrade_pending": database_user_version < CURRENT_DATABASE_VERSION,
|
|
715
721
|
"authenticated": token is not None,
|
|
716
722
|
# Same answer as AuthService.has_password(), from the row already read.
|
|
717
723
|
"has_password": settings is not None and bool(settings.encryption_enabled),
|
|
@@ -68,6 +68,11 @@ from app.usecases.create_child import CmdCreateChild
|
|
|
68
68
|
from app.usecases.create_file_preview_child import CmdCreateFilePreviewChild
|
|
69
69
|
from app.usecases.update_content import CmdUpdateContent
|
|
70
70
|
from app.usecases.prefetch_link_titles import CmdPrefetchLinkTitles
|
|
71
|
+
from app.services.link_title_retry import (
|
|
72
|
+
link_title_retry_snapshot,
|
|
73
|
+
start_link_title_retry,
|
|
74
|
+
stop_link_title_retry,
|
|
75
|
+
)
|
|
71
76
|
from app.usecases.add_selected_text_tag import CmdAddSelectedTextTag
|
|
72
77
|
from app.usecases.tag_proposals import (
|
|
73
78
|
CmdAcceptTagProposal,
|
|
@@ -159,6 +164,26 @@ def prefetch_link_titles(request: Request, draft: LinkTitlePrefetchRequest) -> d
|
|
|
159
164
|
return CmdPrefetchLinkTitles(content=draft.content, tags=draft.tags).execute()
|
|
160
165
|
|
|
161
166
|
|
|
167
|
+
@router.get("/notes/link-titles/retry")
|
|
168
|
+
def link_title_retry_progress(request: Request) -> dict[str, object]:
|
|
169
|
+
require_request_auth_token(request)
|
|
170
|
+
return link_title_retry_snapshot()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@router.post("/notes/link-titles/retry")
|
|
174
|
+
@transactional_route
|
|
175
|
+
def start_link_title_retry_route(request: Request) -> dict[str, object]:
|
|
176
|
+
require_request_auth_token(request)
|
|
177
|
+
return start_link_title_retry()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@router.post("/notes/link-titles/retry/stop")
|
|
181
|
+
@transactional_route
|
|
182
|
+
def stop_link_title_retry_route(request: Request) -> dict[str, object]:
|
|
183
|
+
require_request_auth_token(request)
|
|
184
|
+
return stop_link_title_retry()
|
|
185
|
+
|
|
186
|
+
|
|
162
187
|
def _require_note_present(note_id: str, *, context: str) -> None:
|
|
163
188
|
if not isinstance(context, str) or not context:
|
|
164
189
|
raise ValueError("context must be a non-empty string")
|
|
@@ -45,7 +45,6 @@ def _env_int(name: str, default: int) -> int:
|
|
|
45
45
|
CRASH_SERVER_ON_FAIL = _env_flag("CRASH_SERVER_ON_FAIL", True)
|
|
46
46
|
DEV_ENFORCE_INTEGRITY_CHECKS = _env_flag("DEV_ENFORCE_INTEGRITY_CHECKS", False)
|
|
47
47
|
DISABLE_UNDO_SNAPSHOT = _env_flag("DISABLE_UNDO_SNAPSHOT", True)
|
|
48
|
-
STARTUP_ANIMATION_ENABLED = _env_flag("STARTUP_ANIMATION_ENABLED", False)
|
|
49
48
|
|
|
50
49
|
# Tag suggestions
|
|
51
50
|
TAG_SUGGESTION_CONNECTORS = "-_/."
|
|
@@ -94,6 +94,20 @@ class EncryptionAuditReport:
|
|
|
94
94
|
def startup_allowed(self) -> bool:
|
|
95
95
|
return self.namespace_count > 0 and len(self.fatal_findings) == 0
|
|
96
96
|
|
|
97
|
+
def namespace_statuses(self) -> list[tuple[str, str]]:
|
|
98
|
+
"""(namespace, PASS | MIGRATION REQUIRED | FAIL | SKIPPED (not encrypted)) per namespace."""
|
|
99
|
+
statuses: list[tuple[str, str]] = []
|
|
100
|
+
for result in self.results:
|
|
101
|
+
result_status = "SKIPPED (not encrypted)"
|
|
102
|
+
if result.is_encrypted:
|
|
103
|
+
result_status = "PASS"
|
|
104
|
+
if result.findings:
|
|
105
|
+
result_status = "MIGRATION REQUIRED"
|
|
106
|
+
if any(not finding.is_migration_deferred for finding in result.findings):
|
|
107
|
+
result_status = "FAIL"
|
|
108
|
+
statuses.append((result.namespace, result_status))
|
|
109
|
+
return statuses
|
|
110
|
+
|
|
97
111
|
def render_text(self) -> str:
|
|
98
112
|
status = "FAIL"
|
|
99
113
|
if self.passed:
|
|
@@ -110,15 +124,8 @@ class EncryptionAuditReport:
|
|
|
110
124
|
),
|
|
111
125
|
f"Sensitive payloads checked: {self.checked_payload_count}",
|
|
112
126
|
]
|
|
113
|
-
for
|
|
114
|
-
|
|
115
|
-
if result.is_encrypted:
|
|
116
|
-
result_status = "PASS"
|
|
117
|
-
if result.findings:
|
|
118
|
-
result_status = "MIGRATION REQUIRED"
|
|
119
|
-
if any(not finding.is_migration_deferred for finding in result.findings):
|
|
120
|
-
result_status = "FAIL"
|
|
121
|
-
lines.append(f"- {result.namespace}: {result_status}")
|
|
127
|
+
for namespace, result_status in self.namespace_statuses():
|
|
128
|
+
lines.append(f"- {namespace}: {result_status}")
|
|
122
129
|
if self.findings:
|
|
123
130
|
lines.append("Findings:")
|
|
124
131
|
for finding in self.findings:
|
|
@@ -26,6 +26,8 @@ CAPTURE_BOUNDARIES = {
|
|
|
26
26
|
'app/api/routes/app_updates.py:update_status:lookup': ('AppUpdateRejected', 'FileNotFoundError'),
|
|
27
27
|
# Release smoke polls only its own disposable HTTP listeners during an actual update.
|
|
28
28
|
'scripts/smoke_self_update.py:_has_updated_namespace:probe_capture': ('HTTPError',),
|
|
29
|
+
# Release smoke cleanup: on Windows an exiting process refuses termination; the wait then checks it stopped.
|
|
30
|
+
'scripts/smoke_installed_package.py:_terminate_on_windows:exit_capture': ('ProcessLookupError', 'PermissionError'),
|
|
29
31
|
# A child can exit between poll and terminate; hung children must be killed and reaped.
|
|
30
32
|
'app/services/namespace_switcher.py:_stop_failed_namespace_launch:terminate_capture': ('ProcessLookupError',),
|
|
31
33
|
'app/services/namespace_switcher.py:_stop_failed_namespace_launch:wait_capture': ('TimeoutExpired',),
|
|
@@ -125,6 +127,12 @@ CAPTURE_BOUNDARIES = {
|
|
|
125
127
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
126
128
|
'app/services/link_titles.py:fetch_link_title:target_capture': ('PublicHttpTargetRejected',),
|
|
127
129
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
130
|
+
'app/services/link_titles.py:_fetch_oembed_title:target_capture': ('PublicHttpTargetRejected',),
|
|
131
|
+
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
132
|
+
'app/services/link_titles.py:_fetch_oembed_title:json_capture': ('JSONDecodeError', 'UnicodeDecodeError'),
|
|
133
|
+
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
134
|
+
'app/services/link_titles.py:_download_oembed:capture': ('TimeoutException', 'NetworkError', 'HTTPError', 'TimeoutException', 'NetworkError', 'ProtocolError'),
|
|
135
|
+
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
128
136
|
'app/services/namespace_deletion_worker.py:_is_process_running:kill_capture': ('ProcessLookupError', 'PermissionError'),
|
|
129
137
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
130
138
|
'app/services/namespace_deletion_worker.py:_send_signal_if_running:signal_capture': ('ProcessLookupError',),
|
|
@@ -16,7 +16,7 @@ from app.api.upload_limits import UploadLimitMiddleware
|
|
|
16
16
|
from app.presentation.templates import get_templates
|
|
17
17
|
from .api import dev
|
|
18
18
|
from .api.middleware.auth import AuthMiddleware
|
|
19
|
-
from app.config import ACTIVE_NAMESPACE,
|
|
19
|
+
from app.config import ACTIVE_NAMESPACE, VERSION
|
|
20
20
|
from .db.session import begin_writer, enable_read_guard
|
|
21
21
|
from .db.schema import initialize_schema
|
|
22
22
|
from .db.migrations import CURRENT_DATABASE_VERSION
|
|
@@ -61,6 +61,7 @@ from app.services.diagnostics import track_request
|
|
|
61
61
|
from app.services.diagnostics import write_encrypted_exception_trace
|
|
62
62
|
from app.security.sensitive_logging import traceback_frame_summary
|
|
63
63
|
from app.api.request_auth import clear_auth_cookie
|
|
64
|
+
from app.presentation.login_page import login_is_certainly_needed
|
|
64
65
|
from app.api.routes.notes import router as api2_router
|
|
65
66
|
from app.api.routes.auth import router as api2_auth_router
|
|
66
67
|
from app.api.routes.app_updates import router as api2_app_updates_router
|
|
@@ -463,7 +464,7 @@ async def home(request: Request, db: Annotated[SafeSession, Depends(get_db)]):
|
|
|
463
464
|
asset_version=ASSET_VERSION,
|
|
464
465
|
page_title=_resolve_page_title(base_title="MetaList"),
|
|
465
466
|
needs_auth=True,
|
|
466
|
-
|
|
467
|
+
shows_login_at_once=login_is_certainly_needed(request),
|
|
467
468
|
)
|
|
468
469
|
return template.render(
|
|
469
470
|
request=request,
|
|
@@ -472,10 +473,11 @@ async def home(request: Request, db: Annotated[SafeSession, Depends(get_db)]):
|
|
|
472
473
|
asset_version=ASSET_VERSION,
|
|
473
474
|
page_title=_resolve_page_title(base_title="MetaList"),
|
|
474
475
|
needs_auth=False,
|
|
475
|
-
|
|
476
|
+
shows_login_at_once=False,
|
|
476
477
|
)
|
|
477
478
|
|
|
478
479
|
|
|
480
|
+
|
|
479
481
|
@app.get("/maintenance", response_class=HTMLResponse)
|
|
480
482
|
async def maintenance_page(request: Request):
|
|
481
483
|
"""Maintenance mode page shown during bulk operations."""
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Whether the page opens straight on the login screen (docs/AI-SUMMARY.md, Login screen)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from starlette.requests import Request
|
|
6
|
+
|
|
7
|
+
from app.api.request_auth import AUTH_COOKIE_NAME
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def login_is_certainly_needed(request: Request) -> bool:
|
|
11
|
+
"""Whether a password namespace's page can open on the login screen at once,
|
|
12
|
+
with no white page before the browser checks its session: a re-login was asked
|
|
13
|
+
for (the Session locked page's Go to Login), or the browser has no session."""
|
|
14
|
+
if not isinstance(request, Request):
|
|
15
|
+
raise TypeError("request must be a Request")
|
|
16
|
+
if request.query_params.get("force_reauth") == "1":
|
|
17
|
+
return True
|
|
18
|
+
return request.cookies.get(AUTH_COOKIE_NAME) is None
|
|
@@ -47,6 +47,8 @@ fixed rules, no AI, and it only reacts to pasting: typed text is never changed.
|
|
|
47
47
|
exclusion phrase ("minus" by default) excludes the next term ("neural network
|
|
48
48
|
minus python" gives `neural-network -python`), and a quoted phrase becomes a text
|
|
49
49
|
search. "not" is an ordinary word unless it is set as the exclusion phrase.
|
|
50
|
+
With the cursor inside a quoted phrase (after `"`), a paste is not cleaned up:
|
|
51
|
+
it goes in exactly as copied, on one line, with quote marks escaped.
|
|
50
52
|
- **Tag bar:** words matching no tag become new tags, lowercased unless they look
|
|
51
53
|
like an acronym (`GPT`). Each word is its own tag unless the words together match
|
|
52
54
|
one of the user's tags; a new multi-word tag has to be typed.
|
|
@@ -41,11 +41,14 @@ Sources: docs/ui/content-formatting.md
|
|
|
41
41
|
- Standalone bare URLs, pasted URL-only anchors, and Markdown URL-only links can render as compact cached title links (`title · domain`) when the server already has a successful title fetch for that URL. Custom link labels remain unchanged.
|
|
42
42
|
- Compact note-reference previews reuse the same standalone URL rule, including collapsed embeds and expanded embed source links.
|
|
43
43
|
- Unknown, failed, unsupported, or inline URLs render as raw URL links exactly as before. Failed standalone lookups can expose their status/retry timing through the browser's normal hover tooltip.
|
|
44
|
+
- Lookups are polite to each site (the hostname without `www.`): one request to a site at a time, at least 2 seconds apart, so a note full of links to one site does not trip its rate limit. A site that answers HTTP 429 (too many requests) is left alone for its `Retry-After` time (1 minute to 6 hours; 10 minutes when it gives none), and lookups of its other links wait until then without being recorded as failures. The rate-limited link itself is retried after 10 minutes, 1 hour, 6 hours, 1 day, then weekly.
|
|
44
45
|
- Title fetches are server-side background work; note rendering never waits on network I/O, and edit mode always shows the original stored URL. When background fetches complete, the server increments a link-title revision exposed by `/api2/auth/status`; the browser polling loop batches those changes and triggers a view refresh so newly resolved titles appear without a manual page reload.
|
|
45
46
|
- While editing, the existing 500 ms inactivity check observes the current draft and requests title prefetch after it remains unchanged for at least 600 ms (typically 1–1.5 seconds after input). `POST /api2/notes/link-titles/prefetch` uses the same view-formatting eligibility and background fetch cache without saving the draft or replacing editor HTML. Identical drafts are requested once per editing session; typing and pasting restart the pause.
|
|
46
47
|
- Leaving edit mode always completes a view refresh, including when another view request is in flight. Title revision refreshes defer while editing, then require a refresh so slower lookups appear automatically without disturbing typing.
|
|
47
|
-
-
|
|
48
|
-
-
|
|
48
|
+
- Links to Reddit, YouTube (including `youtu.be`), Vimeo, TikTok, Spotify and SoundCloud first ask the site's public oEmbed service, the preview service those sites provide, for the title. It gives the real post or video title where the page itself is blocked for automated requests or built by JavaScript. The request is paced like any request to that site. A link that forwards elsewhere (a Reddit share link such as `/r/…/s/…` forwards to its post) is also looked up at each address it forwards to. When the service has no usable answer (not a post or video, removed, private), the page is read as for any other site. X is not included: its oEmbed service returns no title.
|
|
49
|
+
- Otherwise, title extraction is generic HTML metadata parsing (`og:title`, `twitter:title`, `meta name=title`, `itemprop=name`, and `<title>`).
|
|
50
|
+
- A title that is only the site's name ("Reddit" for reddit.com, "YouTube", "BBC" for bbc.co.uk, or the domain itself) says nothing the domain does not; it is treated as no title, so the link shows its URL (Reddit's URLs name the subreddit and post). Reddit's generic page titles ("Reddit - Dive into anything") count as no title too. Saved ones are cleared at the next login.
|
|
51
|
+
- Challenge/interstitial titles such as verification, browser-check, or access-denied pages are treated as `no_title` and cleared from existing cache rows on startup/login so they fall back to the raw URL instead of being displayed as valid page titles. So are login, consent and not-found pages, also when the site adds its name: a title is split at the site-name separators (`|`, `·`, `–`, `—`, and ` - ` with spaces) and is not a real title when a part is only a phrase such as "Sign in", "Log in", "Sign up" or "Page not found" ("Sign in - Google Accounts", "Log in | LinkedIn"), or when it contains "before you continue" (YouTube's consent page) or "log in or sign up". Titles that merely mention these words ("How to sign in to Gmail") are kept.
|
|
49
52
|
- Existing rendered anchors are normalized to open in a new browser tab.
|
|
50
53
|
- Clicking a rendered note link (including its title/domain spans) leaves the note in view mode; links do not initiate note dragging. Links inside the active editor keep normal editing behavior.
|
|
51
54
|
- Internal hash-style anchors used by MetaList note-reference UI are left unchanged so in-app reference navigation still works.
|
|
@@ -56,7 +59,7 @@ Sources: docs/ui/content-formatting.md
|
|
|
56
59
|
- Depth 1–3 is supported (e.g. `{{{...}}}`).
|
|
57
60
|
- Wrappers in content are **only consumed/hidden** in view mode when there is a matching *scoped wrapper tag* in the tag bar.
|
|
58
61
|
- If there is **no matching scoped wrapper tag**, wrappers are treated as literal text and remain visible even out of edit mode.
|
|
59
|
-
- When a matching `[[...]]` scoped wrapper tag is active,
|
|
62
|
+
- When a matching `[[...]]` scoped wrapper tag is active, `[[...]]` is formatting syntax, except that `[[UUID]]` containing exactly a note or file UUID is always a link. `![[UUID]]` still renders as an embedded reference.
|
|
60
63
|
|
|
61
64
|
Scoped wrapper tags do not need to be meta tags:
|
|
62
65
|
- Example: tag bar `[foo]` causes all `[...]` regions in the note to render without the brackets in view mode.
|
|
@@ -96,6 +96,7 @@ Opening or dismissing the command palette does not clear undo/redo. Global actio
|
|
|
96
96
|
- `Attach file`: opens the native file picker, uploads the selected file, and inserts an embedded file reference token into the current note. If no note is active, it creates a new note first.
|
|
97
97
|
- `Add Excalidraw diagram`: attaches a new, empty Excalidraw diagram to the current note (or a new note when none is active) and opens the full-screen diagram editor.
|
|
98
98
|
- `Trim unused files`: deletes file rows whose UUIDs are no longer referenced anywhere in note content. This is the only automatic cleanup path for orphaned attachments.
|
|
99
|
+
- `Retry failed link titles`: asks every web link whose title lookup failed (rate limited, refused, login or verification page, no title, timed out, page not found and other errors) again now. It opens a dialog saying how many links it would ask; nothing runs until its **Retry N links** button (or Enter). Unsupported links (such as PDFs) and private-network links are not retried. It uses the usual polite pacing: one request per site at a time, 2 seconds apart; a site that answers "too many requests" is skipped for the rest of the run and its links keep their normal retry schedule. The same dialog then shows progress: links asked, titles found, what still fails and why, and skipped sites. It does not block the app: closing the dialog (×, Escape or a click outside) leaves the retry running, and running the action again shows its progress instead of starting another. **Stop** drops the lookups not yet started; logging out, locking or logging in also stops it. Titles found appear in notes at the next view refresh.
|
|
99
100
|
- `Prioritize tag to front (global)`: opens a warning modal with single-tag input and suggestions from all root notes. Applying it stably moves all matching root notes to the front of the global root order while preserving relative order inside the matching and non-matching groups. Cmd+Z cannot undo this action; the undo/redo queue is cleared.
|
|
100
101
|
- `Prioritize tag to back (global)`: same as above, but stably moves all matching root notes to the back of the global root order.
|
|
101
102
|
- `Alphabetize root notes A-Z (current view)`: after confirmation, permanently rearranges only root-level notes in the active search context by root-note content. Hidden roots and child notes are not reordered. Cmd+Z cannot undo this action; the undo/redo queue is cleared like a view-context switch.
|
|
@@ -112,6 +112,14 @@ loudly; known old-version issues may require authenticated migration. This is a
|
|
|
112
112
|
storage-contract check, not proof of every disk byte being encrypted or a scan
|
|
113
113
|
of all logs/backups/swap. It does not authenticate ciphertext without the key.
|
|
114
114
|
|
|
115
|
+
Logging in: the login screen shows the MetaList logo with the namespace dropdown,
|
|
116
|
+
the password field and OK. A wrong password shows the reason under OK without
|
|
117
|
+
leaving the form. After the password is accepted, a progress bar shows the
|
|
118
|
+
current loading step and the seconds elapsed. When a database upgrade is due,
|
|
119
|
+
"Backing up and upgrading this namespace…" appears under OK while it checks, and
|
|
120
|
+
that login takes longer. "Session locked" means the session moved to another tab
|
|
121
|
+
or device; Go to Login opens the login screen.
|
|
122
|
+
|
|
115
123
|
The Add password, Change password, and Remove password menus open forms. Opening
|
|
116
124
|
is not submitting. An encryption explanation alone does not request a form or a
|
|
117
125
|
password change. Never ask for an actual password or API key in chat.
|
|
@@ -16,7 +16,7 @@ Sources: docs/ui/references.md
|
|
|
16
16
|
- Implemented reference syntaxes:
|
|
17
17
|
- `![[UUID]]` = embedded mode
|
|
18
18
|
- `[[UUID]]` = link mode
|
|
19
|
-
-
|
|
19
|
+
- `[[...]]` containing exactly a note or file UUID is always a link, even when the note has a matching `[[...]]` scoped wrapper tag (for example `[[@LaTeX]]`); other `[[...]]` text is formatted by that wrapper, and links nested inside it still render.
|
|
20
20
|
- A UUID can resolve to:
|
|
21
21
|
- a note
|
|
22
22
|
- a file attachment
|
|
@@ -5,6 +5,15 @@ README. Changes made after the newest listed version are not described here.
|
|
|
5
5
|
Compare with installed_version from the help lookup to tell the user whether
|
|
6
6
|
they already have a release. Version info offers updates (see the data topic).
|
|
7
7
|
|
|
8
|
+
## 0.14.0
|
|
9
|
+
|
|
10
|
+
- A new login screen: one dark screen with the MetaList logo. The namespace, password and OK fade in together; once the password is accepted, the loading progress slides in with the current step and the seconds elapsed. When the first login after an update backs up and upgrades the namespace, a note under OK says so. The Session locked page has the same look, and there is no white flash between them.
|
|
11
|
+
- Web link titles: links to Reddit (including share links), YouTube, Vimeo, TikTok, Spotify and SoundCloud get their real titles. Lookups are paced per site, so a note full of links no longer trips a site's rate limit. Login, consent and site-name-only titles ("Sign in", "Reddit") show the link instead. The new command palette action Retry failed link titles asks every failed link again, with a progress dialog.
|
|
12
|
+
- Quoted search also matches link titles and the URLs hidden behind link labels, and the AI sees those URLs too. Pasting into a quoted search inserts the text as copied.
|
|
13
|
+
- `[[note id]]` is always a link, even in a note with a `[[ ]]` formatting tag.
|
|
14
|
+
- The startup output in the terminal is easier to read: the version, a check mark per check, and each namespace's URLs lined up.
|
|
15
|
+
- Fixed: clicking the AI chat's $ or eye button twice quickly crashed with "Redundant state change".
|
|
16
|
+
|
|
8
17
|
## 0.13.0
|
|
9
18
|
|
|
10
19
|
- Dictation: text from speech-to-text tools such as Superwhisper, pasted into the search bar or any tag field, becomes your existing tags ("neural network" gives `neural-network`). Say "quote … end quote" for text, "minus" to exclude, "at" before meta tags such as `@todo`. In a note, the words after "start tags" go to its tag bar. The phrases are set in Dictation Settings, and one undo restores what was pasted.
|
|
@@ -162,6 +162,15 @@ Text matching is:
|
|
|
162
162
|
- Case-insensitive (`casefold`).
|
|
163
163
|
- Against **visible text**, extracted by stripping HTML (scripts/styles ignored).
|
|
164
164
|
- Also against tag-bar `/* ... */` comment text (whitespace-normalized).
|
|
165
|
+
- Also against the URL of a web link whose label hides it (for example a link
|
|
166
|
+
pasted from a web page that shows a video title): the note is searched as
|
|
167
|
+
"Video title (https://...)".
|
|
168
|
+
- Also against the titles of web pages linked in the note: for each `http(s)` URL
|
|
169
|
+
in the note (written out, or hidden behind a link label), the page title
|
|
170
|
+
MetaList has already fetched and stored. Titles are fetched when a URL on its own
|
|
171
|
+
line is first displayed, so a note matches by title once its title has been
|
|
172
|
+
fetched; a title fetched later makes the note match from then on. Titles are not
|
|
173
|
+
available while the namespace is locked. The URL itself remains searchable.
|
|
165
174
|
- A space at the edge of the quotes marks a word boundary on that side: `"fat "` needs
|
|
166
175
|
the word to end there (a space, punctuation or the end of the text follows), so it
|
|
167
176
|
matches "fat cat" and "fat." but not "father"; `" fat"` needs it to start there, so
|
|
@@ -22,7 +22,7 @@ class BacklinkIndex:
|
|
|
22
22
|
def upsert(self, note_id: str, content: str, tags: str) -> None:
|
|
23
23
|
assert isinstance(note_id, str) and note_id
|
|
24
24
|
counts = dict(Counter(
|
|
25
|
-
token.note_id for token in collect_active_reference_tokens(content
|
|
25
|
+
token.note_id for token in collect_active_reference_tokens(content)
|
|
26
26
|
if token.note_id != note_id
|
|
27
27
|
))
|
|
28
28
|
self.remove(note_id)
|
|
@@ -38,7 +38,7 @@ from app.services.structured_note_renderers import (
|
|
|
38
38
|
)
|
|
39
39
|
from app.services.footnote_rendering import collect_footnotes, finish_footnotes
|
|
40
40
|
from app.services.latex_rendering import render_latex_to_html
|
|
41
|
-
from app.utils.text_utils import HTMLStripper, strip_html
|
|
41
|
+
from app.utils.text_utils import HTMLStripper, LinkUrlKeepingStripper, strip_html
|
|
42
42
|
from app.services.markdown_rendering import render_markdown_to_html
|
|
43
43
|
from app.services.ontology_rules_store import get_ontology_if_ready
|
|
44
44
|
from app.services.link_titles import display_domain_for_url
|
|
@@ -346,8 +346,8 @@ class MetaTagConfig:
|
|
|
346
346
|
scoped_renderers: Mapping[Tuple[str, int], str]
|
|
347
347
|
|
|
348
348
|
|
|
349
|
-
class _AgentNoteText(
|
|
350
|
-
"""
|
|
349
|
+
class _AgentNoteText(LinkUrlKeepingStripper):
|
|
350
|
+
"""Visible text with the URLs link labels hide, and anchor destinations for cached-title lookup."""
|
|
351
351
|
|
|
352
352
|
def __init__(self) -> None:
|
|
353
353
|
super().__init__()
|
|
@@ -361,9 +361,15 @@ class _AgentNoteText(HTMLStripper):
|
|
|
361
361
|
self.anchor_urls.append(value)
|
|
362
362
|
|
|
363
363
|
|
|
364
|
+
def find_plain_text_urls(text: str) -> list[str]:
|
|
365
|
+
"""URLs written out in plain text, in order, without trailing punctuation."""
|
|
366
|
+
if not isinstance(text, str):
|
|
367
|
+
raise TypeError(f"text must be a string, got {type(text)}")
|
|
368
|
+
return [_split_trailing_url_punctuation(match.group(0))[0] for match in _PLAIN_URL_RE.finditer(text)]
|
|
369
|
+
|
|
370
|
+
|
|
364
371
|
def _cached_agent_url_titles(text: str, anchor_urls: list[str], title_lookup: Callable[[str], str | None]) -> list[dict[str, str]]:
|
|
365
|
-
urls = [*anchor_urls, *(
|
|
366
|
-
for match in _PLAIN_URL_RE.finditer(text))]
|
|
372
|
+
urls = [*anchor_urls, *find_plain_text_urls(text)]
|
|
367
373
|
seen = set()
|
|
368
374
|
titles = []
|
|
369
375
|
for url in urls:
|
|
@@ -220,18 +220,15 @@ def replace_reference_token_mode_in_html(
|
|
|
220
220
|
return updated_content, True
|
|
221
221
|
|
|
222
222
|
|
|
223
|
-
def collect_active_reference_tokens(content_html: str
|
|
224
|
-
"""
|
|
223
|
+
def collect_active_reference_tokens(content_html: str) -> List[ReferenceToken]:
|
|
224
|
+
"""The note references the renderer shows: every [[note id]] and ![[note id]].
|
|
225
|
+
|
|
226
|
+
A [[...]] holding exactly a note id is a link even in a note whose tag bar
|
|
227
|
+
has a [[...]] formatting wrapper (docs/ui/references.md).
|
|
228
|
+
"""
|
|
225
229
|
if "[[" not in content_html:
|
|
226
230
|
return []
|
|
227
|
-
|
|
228
|
-
return [
|
|
229
|
-
token for token in collect_reference_tokens_from_html(content_html)
|
|
230
|
-
if _ignored_scoped_square_wrapper_depth_at(
|
|
231
|
-
text=content_html, index=token.start,
|
|
232
|
-
ignored_link_wrapper_keys=ignored_keys, is_embed=token.is_embed,
|
|
233
|
-
) == 0
|
|
234
|
-
]
|
|
231
|
+
return collect_reference_tokens_from_html(content_html)
|
|
235
232
|
|
|
236
233
|
|
|
237
234
|
def render_note_content_with_embeds(
|
|
@@ -458,7 +455,6 @@ def _replace_reference_tokens_in_html(
|
|
|
458
455
|
parts = _HTML_TOKEN_SPLIT_RE.split(content_html)
|
|
459
456
|
output: List[str] = []
|
|
460
457
|
occurrence_index = 0
|
|
461
|
-
ignored_link_wrapper_keys = _ignored_link_wrapper_keys_for_tags(tags)
|
|
462
458
|
for part in parts:
|
|
463
459
|
if _is_html_segment(part):
|
|
464
460
|
output.append(part)
|
|
@@ -469,7 +465,6 @@ def _replace_reference_tokens_in_html(
|
|
|
469
465
|
context=context,
|
|
470
466
|
ancestry=ancestry,
|
|
471
467
|
occurrence_start=occurrence_index,
|
|
472
|
-
ignored_link_wrapper_keys=ignored_link_wrapper_keys,
|
|
473
468
|
static_export=static_export,
|
|
474
469
|
redact_passwords=redact_passwords,
|
|
475
470
|
render_note_embeds_as_links=render_note_embeds_as_links,
|
|
@@ -486,7 +481,6 @@ def _replace_reference_tokens_in_text(
|
|
|
486
481
|
context: EmbedRenderContext,
|
|
487
482
|
ancestry: Tuple[str, ...],
|
|
488
483
|
occurrence_start: int,
|
|
489
|
-
ignored_link_wrapper_keys: FrozenSet[Tuple[str, int]],
|
|
490
484
|
static_export: bool,
|
|
491
485
|
redact_passwords: bool,
|
|
492
486
|
render_note_embeds_as_links: bool,
|
|
@@ -503,17 +497,6 @@ def _replace_reference_tokens_in_text(
|
|
|
503
497
|
output.append(text[index:])
|
|
504
498
|
break
|
|
505
499
|
|
|
506
|
-
ignored_wrapper_depth = _ignored_scoped_square_wrapper_depth_at(
|
|
507
|
-
text=text,
|
|
508
|
-
index=token_start,
|
|
509
|
-
ignored_link_wrapper_keys=ignored_link_wrapper_keys,
|
|
510
|
-
is_embed=is_embed,
|
|
511
|
-
)
|
|
512
|
-
if ignored_wrapper_depth > 0:
|
|
513
|
-
output.append(text[index : token_start + ignored_wrapper_depth])
|
|
514
|
-
index = token_start + ignored_wrapper_depth
|
|
515
|
-
continue
|
|
516
|
-
|
|
517
500
|
output.append(text[index:token_start])
|
|
518
501
|
end = text.find("]]", token_start + token_open_length)
|
|
519
502
|
if end == -1:
|
|
@@ -524,8 +507,10 @@ def _replace_reference_tokens_in_text(
|
|
|
524
507
|
reference_note_id = raw_id.strip()
|
|
525
508
|
|
|
526
509
|
if not _is_valid_embed_note_id(reference_note_id):
|
|
527
|
-
|
|
528
|
-
|
|
510
|
+
# Not a note id (a formatting wrapper or plain brackets): keep the opener
|
|
511
|
+
# and scan on, so a link nested inside, as in [[see [[id]] here]], still counts.
|
|
512
|
+
output.append(text[token_start : token_start + token_open_length])
|
|
513
|
+
index = token_start + token_open_length
|
|
529
514
|
continue
|
|
530
515
|
|
|
531
516
|
output.append(
|
|
@@ -578,8 +563,10 @@ def _collect_reference_tokens_in_text(
|
|
|
578
563
|
)
|
|
579
564
|
)
|
|
580
565
|
occurrence_index += 1
|
|
581
|
-
|
|
582
|
-
|
|
566
|
+
index = token_end_inner + 2
|
|
567
|
+
else:
|
|
568
|
+
# Same rule as rendering: only the opener is skipped, so nested links are found.
|
|
569
|
+
index = token_start + token_open_length
|
|
583
570
|
|
|
584
571
|
return tokens
|
|
585
572
|
|
|
@@ -1213,37 +1200,6 @@ def _render_embedded_note_node(
|
|
|
1213
1200
|
)
|
|
1214
1201
|
|
|
1215
1202
|
|
|
1216
|
-
def _ignored_link_wrapper_keys_for_tags(tags: str) -> FrozenSet[Tuple[str, int]]:
|
|
1217
|
-
consumed_wrapper_keys = find_consumed_content_wrapper_keys(tags)
|
|
1218
|
-
return frozenset(
|
|
1219
|
-
key
|
|
1220
|
-
for key in consumed_wrapper_keys
|
|
1221
|
-
if key[0] == "[" and key[1] >= 2
|
|
1222
|
-
)
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
def _ignored_scoped_square_wrapper_depth_at(
|
|
1226
|
-
*,
|
|
1227
|
-
text: str,
|
|
1228
|
-
index: int,
|
|
1229
|
-
ignored_link_wrapper_keys: FrozenSet[Tuple[str, int]],
|
|
1230
|
-
is_embed: bool,
|
|
1231
|
-
) -> int:
|
|
1232
|
-
if is_embed:
|
|
1233
|
-
return 0
|
|
1234
|
-
for depth in sorted((key[1] for key in ignored_link_wrapper_keys), reverse=True):
|
|
1235
|
-
opener = "[" * depth
|
|
1236
|
-
if not text.startswith(opener, index):
|
|
1237
|
-
continue
|
|
1238
|
-
if index + depth < len(text) and text[index + depth] == "[":
|
|
1239
|
-
continue
|
|
1240
|
-
closer = "]" * depth
|
|
1241
|
-
if text.find(closer, index + depth) == -1:
|
|
1242
|
-
continue
|
|
1243
|
-
return depth
|
|
1244
|
-
return 0
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
1203
|
def _extract_first_line_preview(content_html: str) -> str:
|
|
1248
1204
|
if not isinstance(content_html, str):
|
|
1249
1205
|
raise TypeError("content_html must be a string")
|