MetaList 0.22.0__tar.gz → 0.23.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.22.0/metalist.egg-info → metalist-0.23.0}/PKG-INFO +17 -2
- {metalist-0.22.0 → metalist-0.23.0}/README.md +15 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/note_requests.py +37 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/auth.py +2 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/backups.py +10 -10
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/notes.py +53 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/ontology.py +133 -41
- {metalist-0.22.0 → metalist-0.23.0}/app/api/transactions.py +2 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/db/engine.py +0 -4
- {metalist-0.22.0 → metalist-0.23.0}/app/main.py +15 -15
- {metalist-0.22.0 → metalist-0.23.0}/app/security/authenticated_logging.py +5 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/server_runtime.py +10 -8
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/agent_tools.py +2 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/help_catalog.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-ai.md +3 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-data.md +15 -15
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-dictation.md +3 -4
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-formatting.md +3 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-menus.md +26 -24
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-mouse.md +5 -5
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-notes.md +13 -5
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-ontology.md +6 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-privacy.md +17 -17
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-references.md +11 -11
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-releases.md +15 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-reminders.md +3 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-search.md +4 -4
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/help-tags.md +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/tagging.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/tagging_run.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/app_updates.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/auth_service.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/backup_service.py +2 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/services/bulk_operation.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/dictation_cleanup.py +10 -17
- {metalist-0.22.0 → metalist-0.23.0}/app/services/embedded_references.py +66 -5
- metalist-0.23.0/app/services/find_text.py +119 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/namespace_deletion_jobs.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/namespace_deletion_worker.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/namespace_rename_worker.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/namespace_runtime_guard.py +5 -5
- {metalist-0.22.0 → metalist-0.23.0}/app/services/namespace_switcher.py +42 -42
- {metalist-0.22.0 → metalist-0.23.0}/app/services/note_store.py +7 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/openai_credentials.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/root_sorting.py +32 -4
- {metalist-0.22.0 → metalist-0.23.0}/app/services/search_index.py +39 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/self_update.py +2 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/services/snapshot.py +256 -46
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tab_state.py +98 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/update_backups.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/services/update_preflight.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/config/agent-menu-actions.json +20 -8
- {metalist-0.22.0 → metalist-0.23.0}/app/static/config/command_palette_tags.json +13 -5
- {metalist-0.22.0 → metalist-0.23.0}/app/static/css/main.css +470 -134
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/proposal-menu.js +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/api-client.js +22 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/auth.js +5 -5
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/backup-reminder-schedule.js +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/command-palette-controller.js +5 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/endpoint-registry.js +39 -12
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/tag-config-loader.js +25 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/config.js +1 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/context-menu/context-menu-registry.js +38 -14
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/context-menu/context-menu-service.js +11 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/login-namespace-picker.js +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/ai-agent-settings-modal.js +3 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/backup-restore-modal.js +12 -12
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/backup-result-modal.js +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/backup-settings-modal.js +5 -5
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/delete-namespace-modal.js +22 -22
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/help-modal.js +3 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/memory-usage-modal.js +2 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/namespace-modals.js +46 -46
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/note-layout-appearance-modal.js +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/ontology-modal.js +76 -64
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/session-timeout-modal.js +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/version-info-modal.js +3 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/actions/ui-actions.js +3 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/events/context-menu-events.js +52 -11
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/events/keyboard-events.js +272 -30
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/events/mouse-events.js +35 -4
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/events/search-events.js +25 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/mode-context.js +27 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/dictation-paste-service.js +18 -3
- metalist-0.23.0/app/static/js/modules/mode-manager/services/find-in-list-service.js +779 -0
- metalist-0.23.0/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +606 -0
- metalist-0.23.0/app/static/js/modules/mode-manager/services/reference-view-transition-service.js +206 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +7 -4
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/root-sort-service.js +59 -26
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +7 -2
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-debounce-service.js +5 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-highlight-service.js +3 -2
- metalist-0.23.0/app/static/js/modules/mode-manager/services/search-input-chip-service.js +85 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tab-state-service.js +5 -3
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +3 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/viewport-hold-service.js +67 -8
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/namespace-deleted.js +18 -18
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/namespace-renamed.js +5 -5
- metalist-0.23.0/app/static/js/vendor/dompurify-3.4.17.min.js +7 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/base.html +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/index.html +55 -35
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/namespace_deleted.html +5 -5
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/namespace_renamed.html +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/app/version.py +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/main.py +6 -6
- {metalist-0.22.0 → metalist-0.23.0/metalist.egg-info}/PKG-INFO +17 -2
- {metalist-0.22.0 → metalist-0.23.0}/metalist.egg-info/SOURCES.txt +6 -2
- {metalist-0.22.0 → metalist-0.23.0}/metalist.egg-info/requires.txt +1 -1
- {metalist-0.22.0 → metalist-0.23.0}/pyproject.toml +1 -1
- metalist-0.22.0/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -309
- metalist-0.22.0/app/static/js/vendor/dompurify-3.4.16.min.js +0 -7
- {metalist-0.22.0 → metalist-0.23.0}/MANIFEST.in +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/deps.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/dev.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/middleware/auth.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/request_auth.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/ai.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/app_updates.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/files.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/reminders.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/remote_images.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/routes/test.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/api/upload_limits.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/config.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/contracts.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/data_directory.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/content_migrations_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/editable_files_migration.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/file_schema.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/file_session.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/files_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/link_titles_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/live_recovery.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/migrations.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/notes_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/raw_connection.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/reminders_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/retire_sounds.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/schema.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/search_history_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/session.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/settings_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/tab_state_sql.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/db/version.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/encryption_audit.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/exception_boundaries.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/https_proxy.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/launch_clock.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/models/database.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/models/utils.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/network_settings.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/presentation/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/presentation/login_page.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/presentation/render/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/presentation/templates.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/process_memory.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/crypto_sizes.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/encryption.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/http_error_diagnostics.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/http_headers.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/note_html.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/rendered_html.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/request_boundary.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/request_hosts.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/sensitive_cache.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/sensitive_logging.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/shell_execution.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/security/validation_errors.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/action_log.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/agent_loop.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/ai_send.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/citation_tokens.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/cloud_privacy.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/context.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/evidence_serialization.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/execution_errors.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/export_title_suggestions.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/failure_explanations.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/history.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/inference.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/investigation.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/judging.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/menu_actions.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/model_policy.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/note_aliases.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/note_tag_suggestions.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/openai_cost_tracking.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/openai_inference.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/openai_models.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/privacy_guard.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/prompt_settings.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/prompts/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/prompts/agent.md +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/prompts/final-response.md +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/prompts/system.md +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/release_notes.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/retrieval_settings.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/runtime.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/scope.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skill_settings.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/staged-summary.md +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/tag-proposals.md +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/skills/web-browsing.md +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/staged_summary.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/strict_structured_outputs.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/structured_inference.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/summary_batch_store.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/token_estimation.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/tool_calling.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/trace.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/web_actions.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/web_capabilities.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/web_evidence.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/web_fetch.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/agent/web_settings.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/ai_chat.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/ai_chat_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/ai_chat_stream.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/ai_setup.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/app_update_worker.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/auth.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/auth_cache_state.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/backlink_index.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/backlinks.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/backup_settings_service.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/chess_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/client_state_service.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/code_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/content_cache.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/content_formatting.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/diagnostics.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/diff_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/editing_image_sizes.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/encryption.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/exception_capture.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/file_edit_sessions.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/file_registry.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/file_storage.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/file_text_preview.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/footnote_layout.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/footnote_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/hierarchy.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/html_export.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/html_unformatting.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/hydration_state.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/image_size_formatting.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/inline_image_dimensions.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/inline_image_occurrences.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/input_errors.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/integrity.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/latex_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/link_title_retry.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/link_titles.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/login_rate_limit.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/maintenance_mode.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/markdown_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/memory_breakdown.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/memory_usage.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/mermaid_note_rendering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/note_fullscreen.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/note_image_tags.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/note_ordering.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/ontology_rules_store.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/password_note_fields.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/preference_values.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/public_http.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/reference_presentation.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/reminders.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/remote_image_proxy.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/request_recovery.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/reset_for_tests.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/resource_limits.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/runtime_generation.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/runtime_hardening.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/runtime_lock.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/search_history.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/search_history_storage.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/search_query.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/search_text.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/selected_text_tag.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/session_timeout_service.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/shared_sets.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/shell_session_service.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/store.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/structured_note_renderers.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/sync.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_case.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_details.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_ontology.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_plural_variants.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_rename.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_suggestion_reasons.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_suggestions.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tag_term_matching.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/tokens.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/undo_state.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/update_installer.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/view_cache.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/view_diff.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/view_state.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/services/windows_process_control.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/startup_console.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/startup_environment.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/startup_js_sanity.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/startup_sanity.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/startup_sanity_config.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/startup_shockharness.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/css/floating-notes.css +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/css/forms.css +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/img/favicon.ico +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/img/metalist-logo-black-1024.png +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/img/metalist-logo-black-512.png +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/img/metalist-logo-black.svg +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/img/metalist-logo-white-1024.png +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/img/metalist-logo-white-512.png +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/img/metalist-logo-white.svg +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/locked.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/main.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/agent-web-settings.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-chat-message-placement.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-chat-refused-turns.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-chat-size-limits.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/bulk-scope-question.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/confirmation-card.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/confirmation-question.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/ai-chat/summary-batch-preview.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/api-error-diagnostics.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/api-failure-classification-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/app-notice-stack.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/app-update-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/application-state.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/backup-reminder-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/byte-sizes.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/preferences-store.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/decimal-integer.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/dom-focus.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/elapsed-time.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/excalidraw/excalidraw-actions.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/excalidraw/excalidraw-autosave.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/excalidraw/excalidraw-editor-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/excalidraw/excalidraw-editor-state.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/excalidraw/excalidraw-loader.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/excalidraw/excalidraw-preview-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/excalidraw/excalidraw-scene.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/expected-errors.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/half.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/html-escape.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/http-status.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/list-selection.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/local-date-text.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/maintenance.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/base-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/confirmation-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/dictation-settings-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/export-options-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/link-title-retry-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/password-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/modals/visual-cues-modal.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/dictation-note-paste.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/dictation-paste-padding.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/dropped-file-preview-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/editing-image-size-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/export-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/export-title-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/link-target-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-drag-indicator-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/paste-format-detection-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/paste-format-guess-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/paste-format-offer-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/paste-reference-here-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/print-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/referenced-note-removal-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/right-press-focus-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/root-note-creation-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-highlight-matching.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/mode-manager/services/viewport-reference.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/not-found.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/note-html-sanitizer.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/password-operation-response.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/password-policy.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/password-strength.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/server-rendered-html.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/startup-timing.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/tcp-ports.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/time-units.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/url-tracking-cleaner.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/shockharness/contracts.d.ts +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/shockharness/contracts.js +0 -0
- /metalist-0.22.0/app/static/js/vendor/dompurify-3.4.16.LICENSE.txt → /metalist-0.23.0/app/static/js/vendor/dompurify-3.4.17.LICENSE.txt +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/excalidraw.css +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Bold.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Medium.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Regular.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Virgil/Virgil-Regular.woff2 +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1.LICENSE.txt +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/excalidraw-0.18.1.min.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/static/note-html-policy.json +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/_logo_mark.html +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/locked.html +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/maintenance.html +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/templates/notes_list.html +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/upload_limits.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/add_selected_text_tag.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/base.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/bulk_tag_proposals.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/collapse.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/copy_note.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/create_child.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/create_file_preview_child.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/create_note.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/create_sibling.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/delete_tag.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/expand.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/file_edit_session.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/indent.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/move.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/move_to_top.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/outdent.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/paste_child.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/paste_reference.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/prefetch_link_titles.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/prioritize.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/redo.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/rename_tag.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/resize_image.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/run_shell.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/search_context_tags.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/split_note.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/tag_proposals.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/undo.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/unformat_content.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/usecases/update_content.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/__init__.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/byte_sizes.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/encryption.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/not_found.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/sent_fields.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/tcp_ports.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/text_utils.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/app/utils/time_units.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/convert-from-legacy.py +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.22.0 → metalist-0.23.0}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.22.0 → metalist-0.23.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.23.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://metalist.app
|
|
6
6
|
Project-URL: Repository, https://github.com/metalist-app/metalist
|
|
@@ -36,7 +36,7 @@ Provides-Extra: dev
|
|
|
36
36
|
Requires-Dist: hypothesis==6.164.0; extra == "dev"
|
|
37
37
|
Requires-Dist: pytest==9.1.1; extra == "dev"
|
|
38
38
|
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
|
|
39
|
-
Requires-Dist: shockharness==0.
|
|
39
|
+
Requires-Dist: shockharness==0.26.0; extra == "dev"
|
|
40
40
|
Requires-Dist: mypy==2.4.0; extra == "dev"
|
|
41
41
|
|
|
42
42
|
# MetaList
|
|
@@ -53,6 +53,21 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
53
53
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
54
54
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
55
55
|
|
|
56
|
+
## Changes in 0.23.0
|
|
57
|
+
|
|
58
|
+
- **Reference views.** Following a reference (a link, an embed's reference icon, Go to Source Note) or an AI answer's references slides the list to the left, and a gray chip takes the search box's place: **Source note** (its first line is the tooltip), **Reference** or **All references**. `←` or Escape goes back one level, `×` straight back to your search, each to the exact place you left; the list slides back to the right. With Reduce Motion it is a quick fade. The magnifier beside the chip starts a new search. Reference tabs keep their label and chip after a reload and in every window: no tab is named by a note ID any more.
|
|
59
|
+
- One reference icon, a page with an arrow coming into it, on embeds, links, the chip, the tab list and the right-click menu's **Go to Source Note**; All references has two pages. A collapsed embed shows its source's first line in its own formatting (a green heading stays a green heading), and embeds are a shade darker grey, deeper again for an embed inside an embed.
|
|
60
|
+
- Sort orders and Untagged show as chips inside the search box (`Created`, `Updated`, `A–Z`, `Size`, `Untagged`; the full name is the tooltip). New **Reverse Order** in Sort by works with any order: Z to A, oldest or smallest first, or your own order bottom to top. Typing a new search or leaving a tab ends its sort; a new tab starts unsorted; a reference view and back keeps it.
|
|
61
|
+
- Right-clicking the list offers **Paste Note as Reference at Top** (⌘R) beside Paste Note at Top.
|
|
62
|
+
- Backlinks (`↖`) are hidden for now, until they have a sign of their own.
|
|
63
|
+
- Coming back to a tab, or from a reference view, lands exactly where you were; a note just below the top could put you up to 80px further down.
|
|
64
|
+
- **Find in the list** (Cmd/Ctrl+F) finds text far below the loaded notes and inside folded ones; a folded match opens just for the find.
|
|
65
|
+
- Namespaces are called **vaults** on screen; `--vault` works like `--namespace`.
|
|
66
|
+
- Edit tag relationships: suggestions list tags linked to the focus tag first, a condition shows one part per line, and with no focus tag the `+` buttons are dimmed instead of stopping MetaList.
|
|
67
|
+
- A file link downloads only from its badge and name; a click beside it edits the note.
|
|
68
|
+
- Make Bigger, Make Smaller and Reset Size keep the caret on its side of the image.
|
|
69
|
+
- Logging out while a log entry was being written could close the log under it; the logout now waits.
|
|
70
|
+
|
|
56
71
|
## Changes in 0.22.0
|
|
57
72
|
|
|
58
73
|
- Tag suggestions only narrow as you type, however many letters: `q`, `qu`, `que` keep their order, and a tag that already applies (a parent's, or implied by a rule) stays right after the tags with evidence instead of dropping to the bottom. Each letter after the first answers in a few milliseconds. Measured on a 107,000-note namespace, the wanted tag is in the top five more often after two and three letters (90% and 96%, up from 88% and 93%).
|
|
@@ -12,6 +12,21 @@ 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.23.0
|
|
16
|
+
|
|
17
|
+
- **Reference views.** Following a reference (a link, an embed's reference icon, Go to Source Note) or an AI answer's references slides the list to the left, and a gray chip takes the search box's place: **Source note** (its first line is the tooltip), **Reference** or **All references**. `←` or Escape goes back one level, `×` straight back to your search, each to the exact place you left; the list slides back to the right. With Reduce Motion it is a quick fade. The magnifier beside the chip starts a new search. Reference tabs keep their label and chip after a reload and in every window: no tab is named by a note ID any more.
|
|
18
|
+
- One reference icon, a page with an arrow coming into it, on embeds, links, the chip, the tab list and the right-click menu's **Go to Source Note**; All references has two pages. A collapsed embed shows its source's first line in its own formatting (a green heading stays a green heading), and embeds are a shade darker grey, deeper again for an embed inside an embed.
|
|
19
|
+
- Sort orders and Untagged show as chips inside the search box (`Created`, `Updated`, `A–Z`, `Size`, `Untagged`; the full name is the tooltip). New **Reverse Order** in Sort by works with any order: Z to A, oldest or smallest first, or your own order bottom to top. Typing a new search or leaving a tab ends its sort; a new tab starts unsorted; a reference view and back keeps it.
|
|
20
|
+
- Right-clicking the list offers **Paste Note as Reference at Top** (⌘R) beside Paste Note at Top.
|
|
21
|
+
- Backlinks (`↖`) are hidden for now, until they have a sign of their own.
|
|
22
|
+
- Coming back to a tab, or from a reference view, lands exactly where you were; a note just below the top could put you up to 80px further down.
|
|
23
|
+
- **Find in the list** (Cmd/Ctrl+F) finds text far below the loaded notes and inside folded ones; a folded match opens just for the find.
|
|
24
|
+
- Namespaces are called **vaults** on screen; `--vault` works like `--namespace`.
|
|
25
|
+
- Edit tag relationships: suggestions list tags linked to the focus tag first, a condition shows one part per line, and with no focus tag the `+` buttons are dimmed instead of stopping MetaList.
|
|
26
|
+
- A file link downloads only from its badge and name; a click beside it edits the note.
|
|
27
|
+
- Make Bigger, Make Smaller and Reset Size keep the caret on its side of the image.
|
|
28
|
+
- Logging out while a log entry was being written could close the log under it; the logout now waits.
|
|
29
|
+
|
|
15
30
|
## Changes in 0.22.0
|
|
16
31
|
|
|
17
32
|
- Tag suggestions only narrow as you type, however many letters: `q`, `qu`, `que` keep their order, and a tag that already applies (a parent's, or implied by a rule) stays right after the tags with evidence instead of dropping to the bottom. Each letter after the first answers in a few milliseconds. Measured on a 107,000-note namespace, the wanted tag is in the top five more often after two and three letters (90% and 96%, up from 88% and 93%).
|
|
@@ -56,18 +56,26 @@ class Viewport(TypedDict):
|
|
|
56
56
|
scrollY: Nonnegative
|
|
57
57
|
scrollAnchor: ScrollAnchor | None
|
|
58
58
|
|
|
59
|
+
# A root sort order, and the same order reversed (app/services/root_sorting.py).
|
|
60
|
+
SortMode = Literal[
|
|
61
|
+
'normal', 'created', 'updated', 'alphabetical', 'content-volume',
|
|
62
|
+
'normal-reversed', 'created-reversed', 'updated-reversed', 'alphabetical-reversed', 'content-volume-reversed',
|
|
63
|
+
]
|
|
64
|
+
|
|
59
65
|
@with_config(ConfigDict(strict=True))
|
|
60
66
|
class Tab(TypedDict):
|
|
61
67
|
searchQuery: Text
|
|
62
68
|
scrollY: Nonnegative
|
|
63
69
|
anchorRootId: Text | None
|
|
64
70
|
scrollAnchor: ScrollAnchor | None
|
|
65
|
-
sortMode:
|
|
71
|
+
sortMode: SortMode
|
|
66
72
|
|
|
67
73
|
@with_config(ConfigDict(strict=True))
|
|
68
74
|
class ViewDiffRequest(TypedDict):
|
|
69
75
|
clientId: Identifier
|
|
70
76
|
editingNoteId: Text | None
|
|
77
|
+
# The note find opened to show a match folded away, for this view only (docs/ui/find.md).
|
|
78
|
+
findRevealNoteId: Text | None
|
|
71
79
|
search: Text | None
|
|
72
80
|
tabId: Identifier
|
|
73
81
|
undoContext: UndoContext
|
|
@@ -77,16 +85,42 @@ class ViewDiffRequest(TypedDict):
|
|
|
77
85
|
isUntaggedView: bool
|
|
78
86
|
startAtListEnd: bool
|
|
79
87
|
|
|
88
|
+
# Find in the list (docs/ui/find.md): one step from a root position of the view.
|
|
89
|
+
@with_config(ConfigDict(strict=True))
|
|
90
|
+
class FindInListRequest(TypedDict):
|
|
91
|
+
tabId: Identifier
|
|
92
|
+
search: Text | None
|
|
93
|
+
isUntaggedView: bool
|
|
94
|
+
text: Annotated[str, Field(min_length=1, max_length=KIB)]
|
|
95
|
+
fromRootIndex: Nonnegative
|
|
96
|
+
direction: Literal['forward', 'backward']
|
|
97
|
+
|
|
98
|
+
@with_config(ConfigDict(strict=True))
|
|
99
|
+
class ReferenceOriginScope(TypedDict):
|
|
100
|
+
scopeTabId: Identifier
|
|
101
|
+
searchQuery: Text
|
|
102
|
+
sortMode: SortMode
|
|
103
|
+
isUntaggedView: bool
|
|
104
|
+
|
|
105
|
+
# A tab showing a reference view, opened from another tab (app/services/tab_state.py).
|
|
106
|
+
@with_config(ConfigDict(strict=True))
|
|
107
|
+
class ReferenceView(TypedDict):
|
|
108
|
+
fromTabId: Identifier
|
|
109
|
+
referenceQuery: Text
|
|
110
|
+
viewKind: Literal['source', 'backlinks', 'reference', 'references']
|
|
111
|
+
originScope: ReferenceOriginScope
|
|
112
|
+
|
|
80
113
|
@with_config(ConfigDict(strict=True))
|
|
81
114
|
class UpdateTabStateRequest(TypedDict):
|
|
82
115
|
activeTabId: Identifier
|
|
83
116
|
tabs: dict[Identifier, Tab]
|
|
84
117
|
tabOrder: list[Identifier]
|
|
118
|
+
referenceViews: dict[Identifier, ReferenceView]
|
|
85
119
|
|
|
86
120
|
@with_config(ConfigDict(strict=True))
|
|
87
121
|
class UpdateTabSortModeRequest(TypedDict):
|
|
88
122
|
tabId: Identifier
|
|
89
|
-
sortMode:
|
|
123
|
+
sortMode: SortMode
|
|
90
124
|
clientId: Identifier
|
|
91
125
|
undoContext: UndoContext
|
|
92
126
|
|
|
@@ -126,7 +160,7 @@ class TabSearchInteractionRequest(TypedDict):
|
|
|
126
160
|
class DictationPasteRequest(TypedDict):
|
|
127
161
|
"""Text pasted into the search bar or the tag bar, and the field's current value."""
|
|
128
162
|
text: Text
|
|
129
|
-
target: Literal["search", "tags", "tag"
|
|
163
|
+
target: Literal["search", "tags", "tag"]
|
|
130
164
|
current_value: Text
|
|
131
165
|
# The spoken phrases around a quoted phrase (Dictation Settings).
|
|
132
166
|
quote_open: Identifier
|
|
@@ -1024,7 +1024,7 @@ def namespace_delete_job_status(
|
|
|
1024
1024
|
exc = job_record_capture.captured_exception
|
|
1025
1025
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(exc)) from exc
|
|
1026
1026
|
if job_record is None:
|
|
1027
|
-
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=f"
|
|
1027
|
+
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=f"Vault deletion job not found: {job_id}")
|
|
1028
1028
|
return job_record
|
|
1029
1029
|
|
|
1030
1030
|
|
|
@@ -1038,7 +1038,7 @@ def namespace_rename_job_status(job_id: str):
|
|
|
1038
1038
|
exc = job_record_capture.captured_exception
|
|
1039
1039
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(exc)) from exc
|
|
1040
1040
|
if job_record is None:
|
|
1041
|
-
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=f"
|
|
1041
|
+
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=f"Vault rename job not found: {job_id}")
|
|
1042
1042
|
return job_record
|
|
1043
1043
|
|
|
1044
1044
|
|
|
@@ -301,7 +301,7 @@ def _normalize_selected_namespaces(*, selected_namespaces: list[str]) -> list[st
|
|
|
301
301
|
raise TypeError("selected_namespaces must be a list")
|
|
302
302
|
normalized_selected_namespaces = _order_namespaces(namespaces=selected_namespaces)
|
|
303
303
|
if len(normalized_selected_namespaces) == 0:
|
|
304
|
-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Select at least one
|
|
304
|
+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Select at least one vault to back up")
|
|
305
305
|
return normalized_selected_namespaces
|
|
306
306
|
|
|
307
307
|
|
|
@@ -310,7 +310,7 @@ def _require_existing_selected_namespaces(*, selected_namespaces: list[str]) ->
|
|
|
310
310
|
for namespace in normalized_selected_namespaces:
|
|
311
311
|
database_path = resolve_namespaced_database_path(namespace=namespace)
|
|
312
312
|
if not database_path.is_file():
|
|
313
|
-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=f"Selected
|
|
313
|
+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=f"Selected vault has no database yet: {namespace}")
|
|
314
314
|
return normalized_selected_namespaces
|
|
315
315
|
|
|
316
316
|
|
|
@@ -324,7 +324,7 @@ def _filter_deleted_selected_namespaces(*, selected_namespaces: list[str]) -> li
|
|
|
324
324
|
if len(existing_selected_namespaces) == 0:
|
|
325
325
|
raise HTTPException(
|
|
326
326
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
327
|
-
detail="None of the selected backup
|
|
327
|
+
detail="None of the selected backup vaults still exist",
|
|
328
328
|
)
|
|
329
329
|
return existing_selected_namespaces
|
|
330
330
|
|
|
@@ -583,7 +583,7 @@ def _verify_target_namespace_password(*, target_namespace: str, password: str) -
|
|
|
583
583
|
if not _target_auth_settings_have_password(settings=settings):
|
|
584
584
|
return
|
|
585
585
|
if password == "":
|
|
586
|
-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Target
|
|
586
|
+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Target vault password is required")
|
|
587
587
|
|
|
588
588
|
assert settings is not None
|
|
589
589
|
auth_salt = settings["auth_salt"]
|
|
@@ -610,7 +610,7 @@ def _verify_target_namespace_password(*, target_namespace: str, password: str) -
|
|
|
610
610
|
parallelism,
|
|
611
611
|
).hex()
|
|
612
612
|
if not secrets.compare_digest(candidate, auth_verifier):
|
|
613
|
-
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Target
|
|
613
|
+
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Target vault password is incorrect")
|
|
614
614
|
|
|
615
615
|
|
|
616
616
|
def _collect_import_profile_port_conflicts(
|
|
@@ -633,7 +633,7 @@ def _collect_import_profile_port_conflicts(
|
|
|
633
633
|
continue
|
|
634
634
|
conflict_namespace, conflict_service = occupied_ports[port]
|
|
635
635
|
conflicts.append(
|
|
636
|
-
f"{service} port {port} conflicts with {conflict_service} port reserved for
|
|
636
|
+
f"{service} port {port} conflicts with {conflict_service} port reserved for vault {conflict_namespace}"
|
|
637
637
|
)
|
|
638
638
|
return conflicts
|
|
639
639
|
|
|
@@ -959,7 +959,7 @@ def restore_backup_preflight(
|
|
|
959
959
|
|
|
960
960
|
folder_namespace, folder_filename = _parse_folder_backup_id(payload.backup_id)
|
|
961
961
|
if folder_namespace != backup_namespace:
|
|
962
|
-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup
|
|
962
|
+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup vault does not match payload")
|
|
963
963
|
if folder_filename != payload.backup_filename:
|
|
964
964
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup filename does not match payload")
|
|
965
965
|
settings = load_backup_settings(token=token)
|
|
@@ -1030,7 +1030,7 @@ def restore_backup(
|
|
|
1030
1030
|
|
|
1031
1031
|
folder_namespace, folder_filename = _parse_folder_backup_id(payload.backup_id)
|
|
1032
1032
|
if folder_namespace != backup_namespace:
|
|
1033
|
-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup
|
|
1033
|
+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup vault does not match payload")
|
|
1034
1034
|
if folder_filename != payload.backup_filename:
|
|
1035
1035
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup filename does not match payload")
|
|
1036
1036
|
settings = load_backup_settings(token=token)
|
|
@@ -1101,7 +1101,7 @@ def import_backup(
|
|
|
1101
1101
|
if target_exists and not payload.overwrite_existing_target:
|
|
1102
1102
|
raise HTTPException(
|
|
1103
1103
|
status_code=HTTPStatus.CONFLICT,
|
|
1104
|
-
detail=f"Target
|
|
1104
|
+
detail=f"Target vault already exists: {target_namespace}",
|
|
1105
1105
|
)
|
|
1106
1106
|
if target_exists:
|
|
1107
1107
|
_verify_target_namespace_password(
|
|
@@ -1112,7 +1112,7 @@ def import_backup(
|
|
|
1112
1112
|
target_database_path = resolve_namespaced_database_path(namespace=target_namespace)
|
|
1113
1113
|
folder_namespace, folder_filename = _parse_folder_backup_id(payload.backup_id)
|
|
1114
1114
|
if folder_namespace != backup_namespace:
|
|
1115
|
-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup
|
|
1115
|
+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup vault does not match payload")
|
|
1116
1116
|
if folder_filename != payload.backup_filename:
|
|
1117
1117
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="folder backup filename does not match payload")
|
|
1118
1118
|
settings = load_backup_settings(token=token)
|
|
@@ -11,6 +11,7 @@ from pydantic import BaseModel
|
|
|
11
11
|
|
|
12
12
|
from app.api.note_requests import (
|
|
13
13
|
ViewDiffRequest,
|
|
14
|
+
FindInListRequest,
|
|
14
15
|
UpdateTabStateRequest,
|
|
15
16
|
UpdateTabSortModeRequest,
|
|
16
17
|
CreateNewTabRequest,
|
|
@@ -63,6 +64,7 @@ from app.api.note_requests import (
|
|
|
63
64
|
from app.api.transactions import serialized_read_route, transactional_route
|
|
64
65
|
from app.services.sync import touch_client
|
|
65
66
|
from app.services.snapshot import build_view_state
|
|
67
|
+
from app.services.snapshot import find_in_view
|
|
66
68
|
from app.services.snapshot import resolve_search_scope
|
|
67
69
|
from app.services.snapshot import resolve_view_scope_membership
|
|
68
70
|
from app.services.note_store import store as note_store
|
|
@@ -300,6 +302,7 @@ def view_diff(payload: ViewDiffRequest):
|
|
|
300
302
|
client_id = payload["clientId"]
|
|
301
303
|
touch_client(client_id)
|
|
302
304
|
editing_note_id = payload["editingNoteId"]
|
|
305
|
+
find_reveal_note_id = payload["findRevealNoteId"]
|
|
303
306
|
search = payload["search"]
|
|
304
307
|
tab_id = payload["tabId"]
|
|
305
308
|
undo_context = payload["undoContext"]
|
|
@@ -341,6 +344,10 @@ def view_diff(payload: ViewDiffRequest):
|
|
|
341
344
|
if not note_store.has_note(normalized_editing_note_id):
|
|
342
345
|
normalized_editing_note_id = None
|
|
343
346
|
|
|
347
|
+
# Like editingNoteId, the note find opened can be gone by now (deleted, undone).
|
|
348
|
+
if find_reveal_note_id is not None and not note_store.has_note(find_reveal_note_id):
|
|
349
|
+
find_reveal_note_id = None
|
|
350
|
+
|
|
344
351
|
# The server keeps each tab's warm view (what that browser tab displays),
|
|
345
352
|
# so the browser sends only where it is. A tab with no warm view, or one
|
|
346
353
|
# whose browser shows nothing for it, gets its initial window.
|
|
@@ -357,6 +364,7 @@ def view_diff(payload: ViewDiffRequest):
|
|
|
357
364
|
|
|
358
365
|
state = build_view_state(
|
|
359
366
|
editing_note_id=normalized_editing_note_id,
|
|
367
|
+
find_reveal_note_id=find_reveal_note_id,
|
|
360
368
|
search=normalized_search,
|
|
361
369
|
sort_mode=sort_mode,
|
|
362
370
|
client_known_note_ids=client_known_note_ids,
|
|
@@ -414,17 +422,26 @@ def get_tab_state() -> Dict[str, object]:
|
|
|
414
422
|
@router.post("/notes/tab-state")
|
|
415
423
|
@transactional_route
|
|
416
424
|
def update_tab_state(payload: UpdateTabStateRequest) -> Dict[str, object]:
|
|
417
|
-
if
|
|
418
|
-
|
|
425
|
+
if (
|
|
426
|
+
"activeTabId" not in payload or "tabs" not in payload or "tabOrder" not in payload
|
|
427
|
+
or "referenceViews" not in payload
|
|
428
|
+
):
|
|
429
|
+
raise HTTPException(
|
|
430
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
431
|
+
detail="activeTabId, tabs, tabOrder, and referenceViews are required",
|
|
432
|
+
)
|
|
419
433
|
active_tab_id = payload["activeTabId"]
|
|
420
434
|
tabs = payload["tabs"]
|
|
421
435
|
tab_order = payload["tabOrder"]
|
|
436
|
+
reference_views = payload["referenceViews"]
|
|
422
437
|
if not isinstance(tab_order, list):
|
|
423
438
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="tabOrder must be a list")
|
|
424
439
|
tab_order_list = [str(entry) for entry in tab_order]
|
|
425
440
|
capture = CapturedExceptionContext(InputRejected, boundary='app/api/routes/notes.py:update_tab_state:capture')
|
|
426
441
|
with capture:
|
|
427
|
-
response = tab_state_store.update(
|
|
442
|
+
response = tab_state_store.update(
|
|
443
|
+
active_tab_id=active_tab_id, tabs=tabs, tab_order=tab_order_list, reference_views=reference_views,
|
|
444
|
+
)
|
|
428
445
|
if capture.captured_exception is not None:
|
|
429
446
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Invalid or stale tab state") from capture.captured_exception
|
|
430
447
|
return response
|
|
@@ -632,6 +649,39 @@ def get_memory_usage(request: Request) -> Dict[str, object]:
|
|
|
632
649
|
return describe_memory_usage()
|
|
633
650
|
|
|
634
651
|
|
|
652
|
+
@router.post("/notes/find")
|
|
653
|
+
@transactional_route
|
|
654
|
+
def find_in_list(payload: FindInListRequest) -> Dict[str, object]:
|
|
655
|
+
"""One step of find through the list a tab shows (docs/ui/find.md): the notes the
|
|
656
|
+
text occurs in, in list order, from a root position forward or before it backward."""
|
|
657
|
+
search = payload["search"]
|
|
658
|
+
if search is None or search.strip() == "":
|
|
659
|
+
search = ""
|
|
660
|
+
else:
|
|
661
|
+
# A search that does not parse is answered as rejected input, as the view does.
|
|
662
|
+
parse_search_query(search)
|
|
663
|
+
if payload["text"].strip() == "":
|
|
664
|
+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="text must hold more than spaces")
|
|
665
|
+
window = find_in_view(
|
|
666
|
+
find_text=payload["text"], search=search, sort_mode=_resolve_tab_sort_mode(payload["tabId"]),
|
|
667
|
+
is_untagged_view=payload["isUntaggedView"], from_root_index=payload["fromRootIndex"],
|
|
668
|
+
direction=payload["direction"],
|
|
669
|
+
)
|
|
670
|
+
return {
|
|
671
|
+
"matches": [
|
|
672
|
+
{
|
|
673
|
+
"noteId": match.note_id, "rootId": match.root_id, "rootIndex": match.root_index,
|
|
674
|
+
"contentCount": match.content_count, "commentCount": match.comment_count,
|
|
675
|
+
"previewCount": match.preview_count, "isUnderFoldedNote": match.is_under_folded_note,
|
|
676
|
+
}
|
|
677
|
+
for match in window.matches
|
|
678
|
+
],
|
|
679
|
+
"firstRootIndex": window.first_root_index,
|
|
680
|
+
"endRootIndex": window.end_root_index,
|
|
681
|
+
"rootCount": window.root_count,
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
|
|
635
685
|
@router.get("/notes/memory-usage/breakdown")
|
|
636
686
|
@serialized_read_route
|
|
637
687
|
def get_memory_breakdown(request: Request) -> Dict[str, object]:
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections import Counter
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
3
6
|
from app.utils.byte_sizes import MIB
|
|
4
7
|
from http import HTTPStatus
|
|
5
8
|
from fastapi import APIRouter, HTTPException, Request
|
|
@@ -10,7 +13,12 @@ from pydantic import ConfigDict, Field, with_config
|
|
|
10
13
|
|
|
11
14
|
from app.api.request_auth import get_request_auth_token
|
|
12
15
|
from app.api.transactions import transactional_route
|
|
16
|
+
from app.security.sensitive_cache import SensitiveMemo
|
|
17
|
+
from app.services.resource_limits import SENSITIVE_MEMO_BYTES
|
|
13
18
|
from app.services.search_index import search_index
|
|
19
|
+
from app.services.tag_ontology import TagOntology
|
|
20
|
+
from app.services.tag_term_matching import list_significant_content_match_segments
|
|
21
|
+
from app.utils.not_found import NOT_FOUND
|
|
14
22
|
from app.services.note_store import store as note_store
|
|
15
23
|
from app.services.sync import generate_new_uuid
|
|
16
24
|
from app.services.tag_ontology import RegexAtom, TagAtom, TextAtom, parse_rules_text
|
|
@@ -35,6 +43,15 @@ _EQUALITY_LINE_RULE_COUNT = 2
|
|
|
35
43
|
_PREFIX_MATCH_RANK = 0
|
|
36
44
|
_SUBSTRING_MATCH_RANK = 1
|
|
37
45
|
_FUZZY_MATCH_RANK = 2
|
|
46
|
+
# What a Tag Relationships field adds next to its focus tag; "none" ranks tags by use alone.
|
|
47
|
+
_SUGGESTION_RELATIONS = frozenset({"none", "incoming", "implied", "synonym"})
|
|
48
|
+
# A tag counts as linked to the focus tag once they share this many notes: one shared
|
|
49
|
+
# note is chance.
|
|
50
|
+
_MIN_SHARED_NOTES = 2
|
|
51
|
+
# The focus tags whose related order is kept while their dialog is open (tag names
|
|
52
|
+
# are private: the memo is cleared on lock).
|
|
53
|
+
_RELATED_ORDER_MEMO_ENTRIES = 4
|
|
54
|
+
_related_orders = SensitiveMemo(maxsize=_RELATED_ORDER_MEMO_ENTRIES, max_bytes=SENSITIVE_MEMO_BYTES)
|
|
38
55
|
|
|
39
56
|
|
|
40
57
|
def _maybe_bearer_token(request: Request) -> str:
|
|
@@ -389,27 +406,27 @@ def focus_view(tag: str) -> dict:
|
|
|
389
406
|
for candidate in sorted(left):
|
|
390
407
|
if candidate in equals:
|
|
391
408
|
continue
|
|
392
|
-
|
|
409
|
+
left_rule_ids: set[int] = set()
|
|
393
410
|
for member in equals:
|
|
394
411
|
key = (candidate, member)
|
|
395
412
|
if key in edge_map:
|
|
396
|
-
|
|
397
|
-
if not
|
|
413
|
+
left_rule_ids.add(edge_map[key])
|
|
414
|
+
if not left_rule_ids:
|
|
398
415
|
continue
|
|
399
|
-
direct_left.append({"tag": candidate, "ruleIds": sorted(
|
|
416
|
+
direct_left.append({"tag": candidate, "ruleIds": sorted(left_rule_ids)})
|
|
400
417
|
|
|
401
418
|
for candidate in sorted(right):
|
|
402
419
|
if candidate in equals:
|
|
403
420
|
continue
|
|
404
|
-
|
|
421
|
+
right_rule_ids: set[int] = set()
|
|
405
422
|
for member in equals:
|
|
406
423
|
key = (member, candidate)
|
|
407
424
|
if key in edge_map:
|
|
408
|
-
|
|
409
|
-
if not
|
|
425
|
+
right_rule_ids.add(edge_map[key])
|
|
426
|
+
if not right_rule_ids:
|
|
410
427
|
continue
|
|
411
428
|
direct_right_tags.add(candidate)
|
|
412
|
-
direct_right.append({"tag": candidate, "ruleIds": sorted(
|
|
429
|
+
direct_right.append({"tag": candidate, "ruleIds": sorted(right_rule_ids)})
|
|
413
430
|
|
|
414
431
|
for candidate in sorted(equals):
|
|
415
432
|
if candidate == tag:
|
|
@@ -442,53 +459,128 @@ def focus_view(tag: str) -> dict:
|
|
|
442
459
|
}
|
|
443
460
|
|
|
444
461
|
|
|
462
|
+
@dataclass(frozen=True)
|
|
463
|
+
class _RelatedOrder:
|
|
464
|
+
"""Tags in the order a Tag Relationships field suggests them for its focus tag: linked
|
|
465
|
+
tags first, then tags sharing a word with it, then the rest by use."""
|
|
466
|
+
|
|
467
|
+
index_revision: int
|
|
468
|
+
# Compared by identity: editing the rules compiles a new ontology.
|
|
469
|
+
ontology: TagOntology
|
|
470
|
+
linked: tuple[str, ...]
|
|
471
|
+
named_alike: tuple[str, ...]
|
|
472
|
+
by_use: tuple[str, ...]
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _link_score(*, relation: str, shared: int, focus_notes: int, tag_notes: int) -> float:
|
|
476
|
+
"""How strongly a tag is linked to the focus tag for `relation` (0 to 1)."""
|
|
477
|
+
assert 0 < shared <= tag_notes and shared <= focus_notes, (shared, tag_notes, focus_notes)
|
|
478
|
+
if relation == "incoming":
|
|
479
|
+
# tag => focus: how many of the tag's notes carry the focus tag.
|
|
480
|
+
return shared / tag_notes
|
|
481
|
+
if relation == "implied":
|
|
482
|
+
# focus => tag: how many of the focus tag's notes carry the tag.
|
|
483
|
+
return shared / focus_notes
|
|
484
|
+
assert relation == "synonym", relation
|
|
485
|
+
# Both ways: the notes they share among the notes either is on.
|
|
486
|
+
return shared / (focus_notes + tag_notes - shared)
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def _related_order(*, focus: str, relation: str, tag_counts: dict[str, int]) -> _RelatedOrder:
|
|
490
|
+
ontology = get_ontology()
|
|
491
|
+
key = (focus.casefold(), relation)
|
|
492
|
+
found, kept = _related_orders.lookup(key)
|
|
493
|
+
if found and kept.index_revision == search_index.revision and kept.ontology is ontology:
|
|
494
|
+
return kept
|
|
495
|
+
index_revision = search_index.revision
|
|
496
|
+
focus_notes, written_with_focus = search_index.count_written_tags_on_notes_with(focus)
|
|
497
|
+
left, equal, right = ontology.focus_view(tag=focus)
|
|
498
|
+
# The focus tag, its synonyms, and tags already on this side of it say nothing new.
|
|
499
|
+
excluded = {tag.casefold() for tag in equal} | {focus.casefold()}
|
|
500
|
+
if relation == "incoming":
|
|
501
|
+
excluded |= {tag.casefold() for tag in left}
|
|
502
|
+
elif relation == "implied":
|
|
503
|
+
excluded |= {tag.casefold() for tag in right}
|
|
504
|
+
candidates = [tag for tag in tag_counts if tag.casefold() not in excluded]
|
|
505
|
+
scored = []
|
|
506
|
+
for tag in candidates:
|
|
507
|
+
# A meta tag (@bold, @todo) is formatting or a state, not a topic linked to the
|
|
508
|
+
# focus tag; it is still listed by use, and when "@" is typed.
|
|
509
|
+
if tag.startswith("@") or tag.casefold() not in written_with_focus:
|
|
510
|
+
continue
|
|
511
|
+
tag_shared, tag_notes = written_with_focus[tag.casefold()]
|
|
512
|
+
if tag_shared >= _MIN_SHARED_NOTES:
|
|
513
|
+
score = _link_score(relation=relation, shared=tag_shared, focus_notes=focus_notes, tag_notes=tag_notes)
|
|
514
|
+
scored.append((-score, -tag_shared, tag.casefold(), tag))
|
|
515
|
+
linked = tuple(tag for *_ordering, tag in sorted(scored))
|
|
516
|
+
linked_set = set(linked)
|
|
517
|
+
focus_words = set(list_significant_content_match_segments(focus))
|
|
518
|
+
by_use_order = sorted((tag for tag in candidates if tag not in linked_set), key=lambda tag: (-tag_counts[tag], tag))
|
|
519
|
+
named_alike = tuple(tag for tag in by_use_order if focus_words & set(list_significant_content_match_segments(tag)))
|
|
520
|
+
named_alike_set = set(named_alike)
|
|
521
|
+
order = _RelatedOrder(
|
|
522
|
+
index_revision=index_revision, ontology=ontology, linked=linked, named_alike=named_alike,
|
|
523
|
+
by_use=tuple(tag for tag in by_use_order if tag not in named_alike_set),
|
|
524
|
+
)
|
|
525
|
+
_related_orders.store(key, order)
|
|
526
|
+
return order
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def _match_rank(*, needle: str, tag: str) -> int:
|
|
530
|
+
"""How a typed text matches a tag (prefix, substring or fuzzy), NOT_FOUND if not at all."""
|
|
531
|
+
folded = tag.casefold()
|
|
532
|
+
if folded.startswith(needle):
|
|
533
|
+
return _PREFIX_MATCH_RANK
|
|
534
|
+
if needle in folded:
|
|
535
|
+
return _SUBSTRING_MATCH_RANK
|
|
536
|
+
if _fuzzy_match(needle, folded):
|
|
537
|
+
return _FUZZY_MATCH_RANK
|
|
538
|
+
return NOT_FOUND
|
|
539
|
+
|
|
540
|
+
|
|
445
541
|
@router.get("/tags")
|
|
446
|
-
def list_tags(q: str, limit: int) -> dict:
|
|
447
|
-
|
|
448
|
-
|
|
542
|
+
def list_tags(q: str, limit: int, focus: str, relation: str) -> dict:
|
|
543
|
+
"""Tags for a Tag Relationships field. With a `relation` to `focus`, tags linked to the
|
|
544
|
+
focus tag come first, then tags sharing a word with it, then the rest by use; typing
|
|
545
|
+
narrows that order (app/services/agent/skills/help-ontology.md, "Relationship dialogs"). Without one (`relation` "none",
|
|
546
|
+
`focus` ""), by match, then use."""
|
|
547
|
+
if not isinstance(q, str) or not isinstance(focus, str) or not isinstance(relation, str):
|
|
548
|
+
raise TypeError("q, focus and relation must be strings")
|
|
449
549
|
if not isinstance(limit, int):
|
|
450
550
|
raise TypeError("limit must be an int")
|
|
451
551
|
if limit < 0:
|
|
452
552
|
raise ValueError("limit must be >= 0")
|
|
553
|
+
if relation not in _SUGGESTION_RELATIONS:
|
|
554
|
+
raise ValueError(f"Unknown suggestion relation: {relation!r}")
|
|
555
|
+
if (relation == "none") != (focus == ""):
|
|
556
|
+
raise ValueError("A focus tag goes with a relation, and only with one")
|
|
453
557
|
|
|
454
558
|
ontology = get_ontology()
|
|
455
559
|
# A tag only the rules name is on no note yet.
|
|
456
560
|
tag_counts = {tag: 0 for tag in extract_ontology_tags(ontology)}
|
|
457
561
|
tag_counts.update(search_index.list_tag_frequencies())
|
|
458
|
-
tags = set(tag_counts.keys())
|
|
459
|
-
|
|
460
562
|
needle = q.casefold().strip()
|
|
461
563
|
|
|
564
|
+
if relation != "none":
|
|
565
|
+
order = _related_order(focus=focus, relation=relation, tag_counts=tag_counts)
|
|
566
|
+
ordered: list[str] = []
|
|
567
|
+
for group in (order.linked, order.named_alike):
|
|
568
|
+
ordered.extend(tag for tag in group if needle == "" or _match_rank(needle=needle, tag=tag) != NOT_FOUND)
|
|
569
|
+
rest = [(_match_rank(needle=needle, tag=tag), index, tag) for index, tag in enumerate(order.by_use)]
|
|
570
|
+
ordered.extend(tag for rank, _index, tag in sorted(rest) if needle == "" or rank != NOT_FOUND)
|
|
571
|
+
payload = [{"tag": tag, "count": tag_counts[tag]} for tag in ordered[:limit]]
|
|
572
|
+
return {"totalCount": len(tag_counts), "tags": payload}
|
|
573
|
+
|
|
462
574
|
if needle == "":
|
|
463
|
-
ordered = sorted(
|
|
464
|
-
|
|
465
|
-
payload = [
|
|
466
|
-
{"tag": tag, "count": tag_counts[tag]}
|
|
467
|
-
for tag in ordered
|
|
468
|
-
]
|
|
469
|
-
return {"totalCount": len(tags), "tags": payload}
|
|
575
|
+
ordered = sorted(tag_counts, key=lambda tag: (-tag_counts[tag], tag))[:limit]
|
|
576
|
+
return {"totalCount": len(tag_counts), "tags": [{"tag": tag, "count": tag_counts[tag]} for tag in ordered]}
|
|
470
577
|
|
|
471
578
|
matches: list[tuple[int, int, str]] = []
|
|
472
|
-
for tag in
|
|
473
|
-
|
|
474
|
-
if
|
|
475
|
-
rank
|
|
476
|
-
elif needle in folded:
|
|
477
|
-
rank = _SUBSTRING_MATCH_RANK
|
|
478
|
-
elif _fuzzy_match(needle, folded):
|
|
479
|
-
rank = _FUZZY_MATCH_RANK
|
|
480
|
-
else:
|
|
481
|
-
continue
|
|
482
|
-
count = tag_counts[tag]
|
|
483
|
-
matches.append((rank, -count, tag))
|
|
484
|
-
|
|
579
|
+
for tag in tag_counts:
|
|
580
|
+
rank = _match_rank(needle=needle, tag=tag)
|
|
581
|
+
if rank != NOT_FOUND:
|
|
582
|
+
matches.append((rank, -tag_counts[tag], tag))
|
|
485
583
|
# By rank, then most used, then name.
|
|
486
584
|
matches.sort()
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
payload = [
|
|
491
|
-
{"tag": tag, "count": tag_counts[tag]}
|
|
492
|
-
for tag in results
|
|
493
|
-
]
|
|
494
|
-
return {"totalCount": len(tags), "tags": payload}
|
|
585
|
+
payload = [{"tag": tag, "count": tag_counts[tag]} for _rank, _negative_count, tag in matches[:limit]]
|
|
586
|
+
return {"totalCount": len(tag_counts), "tags": payload}
|
|
@@ -86,7 +86,7 @@ def transactional_route(func: Callable[P, R] | Callable[P, Awaitable[R]]) -> Cal
|
|
|
86
86
|
_check_bulk_guard(func.__name__)
|
|
87
87
|
maintenance = nullcontext()
|
|
88
88
|
if func.__name__ in _STORAGE_TRANSITIONS:
|
|
89
|
-
maintenance = maintenance_service.hold_for_transaction("Updating
|
|
89
|
+
maintenance = maintenance_service.hold_for_transaction("Updating vault storage")
|
|
90
90
|
with maintenance:
|
|
91
91
|
with begin_request_transaction():
|
|
92
92
|
register_runtime_recovery()
|
|
@@ -147,7 +147,7 @@ def assert_mutation_routes_wrapped(app: FastAPI) -> None:
|
|
|
147
147
|
|
|
148
148
|
def _check_bulk_guard(endpoint_name: str) -> None:
|
|
149
149
|
if endpoint_name in _STORAGE_TRANSITIONS and bulk_operation_guard.active_mutations > 1:
|
|
150
|
-
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail="Wait for the current request to finish before changing
|
|
150
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail="Wait for the current request to finish before changing vault storage.")
|
|
151
151
|
# Preferences never touch notes, and every operation reads them once when it
|
|
152
152
|
# starts, so saving them (e.g. the chat panel width) cannot disturb it.
|
|
153
153
|
permitted = {"answer_bulk_question", "preview_cloud_privacy", "put_ai_debug_details", "put_client_preferences"}
|