MetaList 0.23.0__tar.gz → 0.24.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.23.0/metalist.egg-info → metalist-0.24.0}/PKG-INFO +11 -1
- {metalist-0.23.0 → metalist-0.24.0}/README.md +10 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/note_requests.py +12 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/ai.py +10 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/notes.py +82 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/ontology.py +66 -13
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/cloud_privacy.py +50 -2
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/note_tag_suggestions.py +10 -4
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/scope.py +12 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-formatting.md +1 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-menus.md +10 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-mouse.md +1 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-notes.md +3 -2
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-ontology.md +34 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-releases.md +10 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-search.md +50 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-tags.md +18 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/tag-proposals.md +10 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/tagging.py +9 -5
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/tagging_run.py +13 -9
- {metalist-0.23.0 → metalist-0.24.0}/app/services/content_formatting.py +7 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/file_registry.py +63 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/file_storage.py +23 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/html_export.py +11 -5
- {metalist-0.23.0 → metalist-0.24.0}/app/services/note_store.py +59 -7
- {metalist-0.23.0 → metalist-0.24.0}/app/services/ontology_rules_store.py +7 -1
- metalist-0.24.0/app/services/root_date_filter.py +153 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/search_index.py +330 -4
- {metalist-0.23.0 → metalist-0.24.0}/app/services/search_query.py +52 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/search_text.py +6 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/services/snapshot.py +92 -22
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tab_state.py +77 -3
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_ontology.py +196 -2
- metalist-0.24.0/app/services/tag_properties.py +472 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_rename.py +6 -3
- {metalist-0.23.0 → metalist-0.24.0}/app/static/config/agent-menu-actions.json +48 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/config/command_palette_tags.json +32 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/css/main.css +48 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/command-palette-controller.js +114 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/endpoint-registry.js +36 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/config.js +1 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/context-menu-registry.js +93 -7
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/context-menu-service.js +10 -0
- metalist-0.24.0/app/static/js/modules/modals/date-range-modal.js +178 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/help-modal.js +1 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/ontology-modal.js +53 -5
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/ui-actions.js +2 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/context-menu-events.js +132 -10
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/keyboard-events.js +11 -3
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/mouse-events.js +13 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/search-events.js +7 -4
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +2 -1
- metalist-0.24.0/app/static/js/modules/mode-manager/services/date-range-filter-service.js +173 -0
- metalist-0.24.0/app/static/js/modules/mode-manager/services/date-range-kinds.js +20 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +31 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +24 -2
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-syntax-service.js +87 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-state-service.js +26 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +19 -3
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +158 -7
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/index.html +10 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/alphabetize_root_notes.py +1 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/bulk_tag_proposals.py +10 -9
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/move_to_top.py +1 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/reset_updated_at.py +1 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/search_context_tags.py +35 -1
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/set_collapse_in_context.py +21 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/tag_proposals.py +82 -19
- {metalist-0.23.0 → metalist-0.24.0}/app/version.py +1 -1
- {metalist-0.23.0 → metalist-0.24.0/metalist.egg-info}/PKG-INFO +11 -1
- {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/SOURCES.txt +5 -0
- {metalist-0.23.0 → metalist-0.24.0}/MANIFEST.in +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/deps.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/dev.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/middleware/auth.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/request_auth.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/app_updates.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/auth.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/backups.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/files.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/reminders.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/remote_images.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/test.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/transactions.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/api/upload_limits.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/config.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/contracts.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/data_directory.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/content_migrations_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/editable_files_migration.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/engine.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/file_schema.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/file_session.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/files_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/link_titles_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/live_recovery.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/migrations.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/notes_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/raw_connection.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/reminders_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/retire_sounds.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/schema.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/search_history_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/session.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/settings_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/tab_state_sql.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/db/version.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/encryption_audit.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/exception_boundaries.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/https_proxy.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/launch_clock.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/main.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/models/database.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/models/utils.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/network_settings.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/presentation/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/presentation/login_page.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/presentation/render/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/presentation/templates.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/process_memory.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/authenticated_logging.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/crypto_sizes.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/encryption.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/http_error_diagnostics.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/http_headers.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/note_html.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/rendered_html.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/request_boundary.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/request_hosts.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/sensitive_cache.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/sensitive_logging.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/shell_execution.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/security/validation_errors.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/server_runtime.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/action_log.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/agent_loop.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/agent_tools.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/ai_send.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/citation_tokens.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/context.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/evidence_serialization.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/execution_errors.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/export_title_suggestions.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/failure_explanations.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/help_catalog.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/history.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/inference.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/investigation.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/judging.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/menu_actions.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/model_policy.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/note_aliases.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/openai_cost_tracking.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/openai_inference.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/openai_models.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/privacy_guard.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompt_settings.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/agent.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/final-response.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/system.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/release_notes.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/retrieval_settings.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/runtime.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skill_settings.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-ai.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-data.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-dictation.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-privacy.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-references.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-reminders.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/staged-summary.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/web-browsing.md +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/staged_summary.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/strict_structured_outputs.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/structured_inference.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/summary_batch_store.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/token_estimation.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/tool_calling.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/trace.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_actions.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_capabilities.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_evidence.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_fetch.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_settings.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_chat.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_chat_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_chat_stream.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_setup.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/app_update_worker.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/app_updates.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/auth.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/auth_cache_state.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/auth_service.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/backlink_index.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/backlinks.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/backup_service.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/backup_settings_service.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/bulk_operation.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/chess_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/client_state_service.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/code_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/content_cache.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/diagnostics.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/dictation_cleanup.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/diff_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/editing_image_sizes.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/embedded_references.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/encryption.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/exception_capture.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/file_edit_sessions.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/file_text_preview.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/find_text.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/footnote_layout.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/footnote_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/hierarchy.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/html_unformatting.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/hydration_state.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/image_size_formatting.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/inline_image_dimensions.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/inline_image_occurrences.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/input_errors.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/integrity.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/latex_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/link_title_retry.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/link_titles.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/login_rate_limit.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/maintenance_mode.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/markdown_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/memory_breakdown.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/memory_usage.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/mermaid_note_rendering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_deletion_worker.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_rename_worker.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_runtime_guard.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_switcher.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/note_fullscreen.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/note_image_tags.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/note_ordering.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/openai_credentials.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/password_note_fields.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/preference_values.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/public_http.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/reference_presentation.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/reminders.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/remote_image_proxy.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/request_recovery.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/reset_for_tests.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/resource_limits.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/root_sorting.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/runtime_generation.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/runtime_hardening.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/runtime_lock.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/search_history.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/search_history_storage.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/selected_text_tag.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/self_update.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/session_timeout_service.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/shared_sets.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/shell_session_service.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/store.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/structured_note_renderers.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/sync.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_case.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_details.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_plural_variants.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_suggestion_reasons.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_suggestions.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_term_matching.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/tokens.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/undo_state.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/update_backups.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/update_installer.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/update_preflight.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/view_cache.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/view_diff.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/view_state.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/services/windows_process_control.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/startup_console.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/startup_environment.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/startup_js_sanity.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/startup_sanity.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/startup_sanity_config.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/startup_shockharness.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/css/floating-notes.css +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/css/forms.css +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/img/favicon.ico +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-black-1024.png +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-black-512.png +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-black.svg +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-white-1024.png +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-white-512.png +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-white.svg +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/locked.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/main.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/agent-web-settings.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-message-placement.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-refused-turns.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-size-limits.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/bulk-scope-question.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/confirmation-card.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/confirmation-question.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/summary-batch-preview.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/api-client.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/api-error-diagnostics.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/api-failure-classification-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/app-notice-stack.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/app-update-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/application-state.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/auth.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/backup-reminder-schedule.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/backup-reminder-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/byte-sizes.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/preferences-store.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/decimal-integer.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/dom-focus.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/elapsed-time.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-actions.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-autosave.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-editor-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-editor-state.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-loader.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-preview-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-scene.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/expected-errors.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/half.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/html-escape.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/http-status.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/list-selection.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/local-date-text.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/login-namespace-picker.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/maintenance.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/ai-agent-settings-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/backup-result-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/base-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/confirmation-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/dictation-settings-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/export-options-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/link-title-retry-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/memory-usage-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-modals.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/password-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/version-info-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/visual-cues-modal.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/mode-context.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dictation-note-paste.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dictation-paste-padding.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dictation-paste-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dropped-file-preview-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/editing-image-size-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/export-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/export-title-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/find-in-list-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/link-target-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-drag-indicator-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-format-detection-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-format-guess-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-format-offer-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-reference-here-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/print-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/reference-view-transition-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/referenced-note-removal-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/right-press-focus-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-note-creation-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-highlight-matching.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-highlight-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-input-chip-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/viewport-hold-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/viewport-reference.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/not-found.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/note-html-sanitizer.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-operation-response.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-policy.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-strength.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/server-rendered-html.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/startup-timing.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/tcp-ports.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/time-units.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/url-tracking-cleaner.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/namespace-deleted.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/namespace-renamed.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/shockharness/contracts.d.ts +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/shockharness/contracts.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/dompurify-3.4.17.LICENSE.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/dompurify-3.4.17.min.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/excalidraw.css +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Bold.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Medium.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Regular.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Virgil/Virgil-Regular.woff2 +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1.LICENSE.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1.min.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/static/note-html-policy.json +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/_logo_mark.html +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/base.html +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/locked.html +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/maintenance.html +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/namespace_deleted.html +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/namespace_renamed.html +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/templates/notes_list.html +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/upload_limits.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/add_selected_text_tag.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/base.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/collapse.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/copy_note.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_child.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_file_preview_child.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_note.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_sibling.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/delete_tag.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/expand.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/file_edit_session.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/indent.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/move.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/outdent.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/paste_child.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/paste_reference.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/prefetch_link_titles.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/prioritize.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/redo.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/rename_tag.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/resize_image.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/run_shell.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/split_note.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/undo.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/unformat_content.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/usecases/update_content.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/__init__.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/byte_sizes.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/encryption.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/not_found.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/sent_fields.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/tcp_ports.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/text_utils.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/app/utils/time_units.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/convert-from-legacy.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/main.py +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/requires.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/pyproject.toml +0 -0
- {metalist-0.23.0 → metalist-0.24.0}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.23.0 → metalist-0.24.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.24.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
|
|
@@ -53,6 +53,16 @@ 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.24.0
|
|
57
|
+
|
|
58
|
+
- **Super tags.** A tag can carry values: `jogging:miles=3:duration=30`, `drug:dosage=10mg`, `run:start=10:30pm`. Search by them with `jogging:miles>2`, `jogging:miles?` (notes missing it), `date>=2024-01`, or `jogging:miles=MAX` / `=MIN` for the largest or smallest among the notes found. Values compare as numbers (a unit is a label: `dosage>5mg` compares only mg, `dosage>5` every unit), dates, times (`10:30pm` = `22:30`) or text. A search reads values through tag rules too: with `jogging => exercise`, `exercise:miles>2` finds your runs. The tag bar and the search box suggest the property names and units you already use, and `MAX`/`MIN` after `=`. A plain `jogging` search still finds `jogging:miles=3`; children inherit the tag, never its values.
|
|
59
|
+
- Tag rules can test values: `jogging:miles>10 => long-run`, `task:due? => needs-date`. The tag a rule gives passes to the note's children; Edit Tag Relationships shows such a rule in the left column of the tag it gives, suggests names and units while you type one, and warns about a property no note has (a typo). Saving one re-tags only the notes it can concern.
|
|
60
|
+
- The AI can propose super tags with values a note states (`jogging:miles=3` for "ran 3 miles"), reusing your property names and units; accepting one adds its values to the note's tag.
|
|
61
|
+
- **Date range** (right-click menu, search box menu and command palette): show only notes created, or last updated, today, in the last 7 or 30 days, this year, or in a custom range. A chip in the search box names it; its `×`, a new search or leaving the tab ends it.
|
|
62
|
+
- File names are searchable: a quoted search (`"congratulation"`) and find (Cmd/Ctrl+F) match the names of files a note holds, and the AI sees them.
|
|
63
|
+
- ⌘+ / ⌘− with the pointer on a picture or diagram makes it bigger or smaller, viewing or editing.
|
|
64
|
+
- Right-clicking the search box past what you typed offers View, Sort by and Date range.
|
|
65
|
+
|
|
56
66
|
## Changes in 0.23.0
|
|
57
67
|
|
|
58
68
|
- **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.
|
|
@@ -12,6 +12,16 @@ 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.24.0
|
|
16
|
+
|
|
17
|
+
- **Super tags.** A tag can carry values: `jogging:miles=3:duration=30`, `drug:dosage=10mg`, `run:start=10:30pm`. Search by them with `jogging:miles>2`, `jogging:miles?` (notes missing it), `date>=2024-01`, or `jogging:miles=MAX` / `=MIN` for the largest or smallest among the notes found. Values compare as numbers (a unit is a label: `dosage>5mg` compares only mg, `dosage>5` every unit), dates, times (`10:30pm` = `22:30`) or text. A search reads values through tag rules too: with `jogging => exercise`, `exercise:miles>2` finds your runs. The tag bar and the search box suggest the property names and units you already use, and `MAX`/`MIN` after `=`. A plain `jogging` search still finds `jogging:miles=3`; children inherit the tag, never its values.
|
|
18
|
+
- Tag rules can test values: `jogging:miles>10 => long-run`, `task:due? => needs-date`. The tag a rule gives passes to the note's children; Edit Tag Relationships shows such a rule in the left column of the tag it gives, suggests names and units while you type one, and warns about a property no note has (a typo). Saving one re-tags only the notes it can concern.
|
|
19
|
+
- The AI can propose super tags with values a note states (`jogging:miles=3` for "ran 3 miles"), reusing your property names and units; accepting one adds its values to the note's tag.
|
|
20
|
+
- **Date range** (right-click menu, search box menu and command palette): show only notes created, or last updated, today, in the last 7 or 30 days, this year, or in a custom range. A chip in the search box names it; its `×`, a new search or leaving the tab ends it.
|
|
21
|
+
- File names are searchable: a quoted search (`"congratulation"`) and find (Cmd/Ctrl+F) match the names of files a note holds, and the AI sees them.
|
|
22
|
+
- ⌘+ / ⌘− with the pointer on a picture or diagram makes it bigger or smaller, viewing or editing.
|
|
23
|
+
- Right-clicking the search box past what you typed offers View, Sort by and Date range.
|
|
24
|
+
|
|
15
25
|
## Changes in 0.23.0
|
|
16
26
|
|
|
17
27
|
- **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.
|
|
@@ -124,6 +124,18 @@ class UpdateTabSortModeRequest(TypedDict):
|
|
|
124
124
|
clientId: Identifier
|
|
125
125
|
undoContext: UndoContext
|
|
126
126
|
|
|
127
|
+
@with_config(ConfigDict(strict=True))
|
|
128
|
+
class UpdateTabDateFilterRequest(TypedDict):
|
|
129
|
+
tabId: Identifier
|
|
130
|
+
field: Literal["created", "updated"]
|
|
131
|
+
# "none" shows every date again.
|
|
132
|
+
rangeKind: Literal["none", "today", "last-7-days", "last-30-days", "this-year", "custom"]
|
|
133
|
+
# A custom range's ends (YYYY-MM-DD); "" for an open end, and for every other range.
|
|
134
|
+
fromDate: Text
|
|
135
|
+
toDate: Text
|
|
136
|
+
clientId: Identifier
|
|
137
|
+
undoContext: UndoContext
|
|
138
|
+
|
|
127
139
|
@with_config(ConfigDict(strict=True))
|
|
128
140
|
class CreateNewTabRequest(TypedDict):
|
|
129
141
|
copyFromTabId: Identifier
|
|
@@ -498,6 +498,7 @@ def suggest_tags_for_note_with_ai(
|
|
|
498
498
|
scope = resolve_view_scope_membership(
|
|
499
499
|
search=payload.search,
|
|
500
500
|
sort_mode=tab_state_store.get_sort_mode(tab_id=payload.tab_id),
|
|
501
|
+
date_filter=tab_state_store.get_date_filter(tab_id=payload.tab_id),
|
|
501
502
|
is_untagged_view=payload.is_untagged_view,
|
|
502
503
|
)
|
|
503
504
|
if note_id not in scope.allowed_note_ids:
|
|
@@ -559,6 +560,7 @@ def _export_title_request(scope: ExportTitleScope, token: str) -> ExportTitleReq
|
|
|
559
560
|
root_ids, allowed_note_ids = resolve_export_scope(
|
|
560
561
|
search=search,
|
|
561
562
|
sort_mode=tab_state_store.get_sort_mode(tab_id=scope.tab_id),
|
|
563
|
+
date_filter=tab_state_store.get_date_filter(tab_id=scope.tab_id),
|
|
562
564
|
is_untagged_view=scope.is_untagged_view, root_note_id=note_id,
|
|
563
565
|
)
|
|
564
566
|
boundary = resolve_cloud_privacy_boundary(preferences=load_client_preferences(token=token), provider=scope.provider)
|
|
@@ -903,21 +905,26 @@ def stream_ai_chat(
|
|
|
903
905
|
authoritative_sort_mode = tab_state_store.get_sort_mode(
|
|
904
906
|
tab_id=payload.scope.scope_tab_id
|
|
905
907
|
)
|
|
908
|
+
authoritative_date_filter = tab_state_store.get_date_filter(tab_id=payload.scope.scope_tab_id)
|
|
906
909
|
active_search_query = authoritative_search_query
|
|
907
910
|
active_sort_mode = authoritative_sort_mode
|
|
911
|
+
active_date_filter = authoritative_date_filter
|
|
908
912
|
if payload.selected_note_id and payload.scope.active_tab_id != payload.scope.scope_tab_id:
|
|
909
913
|
active_search_query = tab_state_store.get_search_query(tab_id=authoritative_active_tab_id)
|
|
910
914
|
active_sort_mode = tab_state_store.get_sort_mode(tab_id=authoritative_active_tab_id)
|
|
915
|
+
active_date_filter = tab_state_store.get_date_filter(tab_id=authoritative_active_tab_id)
|
|
911
916
|
frozen_scope = scoped_search_snapshot_factory.freeze(
|
|
912
917
|
descriptor=payload.scope,
|
|
913
918
|
authoritative_search_query=authoritative_search_query,
|
|
914
919
|
authoritative_sort_mode=authoritative_sort_mode,
|
|
920
|
+
authoritative_date_filter=authoritative_date_filter,
|
|
915
921
|
run_id=str(uuid4()),
|
|
916
922
|
session_key=session_key,
|
|
917
923
|
privacy_boundary=privacy_boundary,
|
|
918
924
|
selected_note_id=payload.selected_note_id,
|
|
919
925
|
authoritative_active_search_query=active_search_query,
|
|
920
926
|
authoritative_active_sort_mode=active_sort_mode,
|
|
927
|
+
authoritative_active_date_filter=active_date_filter,
|
|
921
928
|
)
|
|
922
929
|
tagging_run = TaggingRun(token=token, snapshot=frozen_scope, privacy_boundary=privacy_boundary,
|
|
923
930
|
preferences=preferences, sync_uuid=get_current_sync_uuid(),
|
|
@@ -1054,7 +1061,9 @@ def manage_bulk_proposals(payload: BulkManageRequest, token: Annotated[str, Depe
|
|
|
1054
1061
|
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail="Search context changed")
|
|
1055
1062
|
async def execute():
|
|
1056
1063
|
with bulk_operation_guard.acquire(token_service.get_session_key(token)):
|
|
1057
|
-
note_ids = proposal_scope_ids(
|
|
1064
|
+
note_ids = proposal_scope_ids(
|
|
1065
|
+
payload.scope, date_filter=tab_state_store.get_date_filter(tab_id=payload.scope.scope_tab_id),
|
|
1066
|
+
)
|
|
1058
1067
|
if payload.target == "namespace":
|
|
1059
1068
|
note_ids = tuple(note_store.list_note_ids())
|
|
1060
1069
|
changes, count, _ = prepare_proposal_changes(
|
|
@@ -13,6 +13,7 @@ from app.api.note_requests import (
|
|
|
13
13
|
ViewDiffRequest,
|
|
14
14
|
FindInListRequest,
|
|
15
15
|
UpdateTabStateRequest,
|
|
16
|
+
UpdateTabDateFilterRequest,
|
|
16
17
|
UpdateTabSortModeRequest,
|
|
17
18
|
CreateNewTabRequest,
|
|
18
19
|
DeleteTabRequest,
|
|
@@ -63,6 +64,14 @@ from app.api.note_requests import (
|
|
|
63
64
|
)
|
|
64
65
|
from app.api.transactions import serialized_read_route, transactional_route
|
|
65
66
|
from app.services.sync import touch_client
|
|
67
|
+
from app.services.root_date_filter import DATE_RANGE_NONE
|
|
68
|
+
from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_SEARCH
|
|
69
|
+
from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_TAG_BAR
|
|
70
|
+
from app.services.tag_properties import PropertySuggestion
|
|
71
|
+
from app.services.tag_properties import has_property_syntax
|
|
72
|
+
from app.services.tag_properties import is_property_term
|
|
73
|
+
from app.services.root_date_filter import RootDateFilter
|
|
74
|
+
from app.services.root_date_filter import make_root_date_filter
|
|
66
75
|
from app.services.snapshot import build_view_state
|
|
67
76
|
from app.services.snapshot import find_in_view
|
|
68
77
|
from app.services.snapshot import resolve_search_scope
|
|
@@ -262,6 +271,13 @@ def _resolve_tab_sort_mode(tab_id: object) -> str:
|
|
|
262
271
|
return sort_mode
|
|
263
272
|
|
|
264
273
|
|
|
274
|
+
def _resolve_tab_date_filter(tab_id: str) -> RootDateFilter | None:
|
|
275
|
+
"""The tab's date range filter (None: every date), as its sort order is resolved."""
|
|
276
|
+
if not isinstance(tab_id, str) or tab_id == "":
|
|
277
|
+
raise TypeError("tabId must be a non-empty string")
|
|
278
|
+
return tab_state_store.get_date_filter(tab_id=tab_id)
|
|
279
|
+
|
|
280
|
+
|
|
265
281
|
def _block_root_reorder_when_sorted(note_id: str, *, tab_id: object, new_parent_id: object) -> None:
|
|
266
282
|
sort_mode = _resolve_tab_sort_mode(tab_id)
|
|
267
283
|
if not is_root_reorder_locked(sort_mode):
|
|
@@ -367,6 +383,7 @@ def view_diff(payload: ViewDiffRequest):
|
|
|
367
383
|
find_reveal_note_id=find_reveal_note_id,
|
|
368
384
|
search=normalized_search,
|
|
369
385
|
sort_mode=sort_mode,
|
|
386
|
+
date_filter=_resolve_tab_date_filter(tab_id),
|
|
370
387
|
client_known_note_ids=client_known_note_ids,
|
|
371
388
|
previous_root_ids=previous_root_ids,
|
|
372
389
|
visible_top_root_id=visible_top_root_id,
|
|
@@ -474,6 +491,23 @@ def update_tab_sort_mode(payload: UpdateTabSortModeRequest) -> Dict[str, object]
|
|
|
474
491
|
return response
|
|
475
492
|
|
|
476
493
|
|
|
494
|
+
@router.post("/notes/tab-state/date-filter")
|
|
495
|
+
@transactional_route
|
|
496
|
+
def update_tab_date_filter(payload: UpdateTabDateFilterRequest) -> Dict[str, object]:
|
|
497
|
+
"""Set or clear a tab's date range filter (root_date_filter.py). A range that is
|
|
498
|
+
not one (its start after its end, say) is answered as rejected input."""
|
|
499
|
+
date_filter: RootDateFilter | None = None
|
|
500
|
+
if payload["rangeKind"] != DATE_RANGE_NONE:
|
|
501
|
+
date_filter = make_root_date_filter(
|
|
502
|
+
field=payload["field"], range_kind=payload["rangeKind"],
|
|
503
|
+
from_date=payload["fromDate"], to_date=payload["toDate"],
|
|
504
|
+
)
|
|
505
|
+
response = tab_state_store.set_date_filter(tab_id=payload["tabId"], date_filter=date_filter)
|
|
506
|
+
if response["changed"] is True:
|
|
507
|
+
reset_undo_stack(payload["clientId"], payload["undoContext"])
|
|
508
|
+
return response
|
|
509
|
+
|
|
510
|
+
|
|
477
511
|
@router.post("/notes/tab-state/new-tab")
|
|
478
512
|
@transactional_route
|
|
479
513
|
def create_new_tab(payload: CreateNewTabRequest) -> Dict[str, object]:
|
|
@@ -523,6 +557,15 @@ def search_suggestions(request: Request, payload: SearchSuggestionsRequest) -> D
|
|
|
523
557
|
)
|
|
524
558
|
window_days = tuple(raw_window_days)
|
|
525
559
|
validate_tag_activity_windows(window_days)
|
|
560
|
+
# Typing a property term (exercise:mi, drug:dosage>5): its names or units.
|
|
561
|
+
typed_term = _typed_property_term(query)
|
|
562
|
+
if typed_term is not None:
|
|
563
|
+
return _property_suggestions_response(
|
|
564
|
+
search_index.suggest_property_completions(
|
|
565
|
+
typed=typed_term, place=PROPERTY_SUGGESTIONS_IN_SEARCH, limit=MAX_SEARCH_SUGGESTIONS,
|
|
566
|
+
),
|
|
567
|
+
personalized=True,
|
|
568
|
+
)
|
|
526
569
|
all_suggestions = search_index.suggest_all_tag_completions(query=query)
|
|
527
570
|
suggestions = all_suggestions[:MAX_SEARCH_SUGGESTIONS]
|
|
528
571
|
personalized_selections: list[TagActivityWindowSelection] = []
|
|
@@ -561,9 +604,33 @@ def search_suggestions(request: Request, payload: SearchSuggestionsRequest) -> D
|
|
|
561
604
|
tag: list(search_suggestion_reasons(facts=facts, term=tag, recent_activity=recent_activity))
|
|
562
605
|
for tag in suggestions
|
|
563
606
|
},
|
|
607
|
+
"labels": {tag: tag for tag in suggestions},
|
|
564
608
|
}
|
|
565
609
|
|
|
566
610
|
|
|
611
|
+
def _typed_property_term(query: str) -> str | None:
|
|
612
|
+
"""The property term being typed at the end of a search, without its - or +."""
|
|
613
|
+
if query == "" or query[-1].isspace():
|
|
614
|
+
return None
|
|
615
|
+
term = query.split()[-1].lstrip("+-")
|
|
616
|
+
if '"' in term or "'" in term or not is_property_term(term):
|
|
617
|
+
return None
|
|
618
|
+
return term
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def _property_suggestions_response(suggestions: list[PropertySuggestion], *, personalized: bool) -> Dict[str, object]:
|
|
622
|
+
"""Property names or units as the suggestion lists take them: the full replacement,
|
|
623
|
+
the part the list shows (miles= for jogging:miles=) and why."""
|
|
624
|
+
response: Dict[str, object] = {
|
|
625
|
+
"suggestions": [suggestion.replacement for suggestion in suggestions],
|
|
626
|
+
"reasons": {suggestion.replacement: list(suggestion.reasons) for suggestion in suggestions},
|
|
627
|
+
"labels": {suggestion.replacement: suggestion.label for suggestion in suggestions},
|
|
628
|
+
}
|
|
629
|
+
if personalized:
|
|
630
|
+
response["personalizedSuggestions"] = []
|
|
631
|
+
return response
|
|
632
|
+
|
|
633
|
+
|
|
567
634
|
@router.post("/notes/prioritize-tag-suggestions")
|
|
568
635
|
@transactional_route
|
|
569
636
|
def prioritize_tag_suggestions(payload: PrioritizeTagSuggestionsRequest) -> Dict[str, object]:
|
|
@@ -664,6 +731,7 @@ def find_in_list(payload: FindInListRequest) -> Dict[str, object]:
|
|
|
664
731
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="text must hold more than spaces")
|
|
665
732
|
window = find_in_view(
|
|
666
733
|
find_text=payload["text"], search=search, sort_mode=_resolve_tab_sort_mode(payload["tabId"]),
|
|
734
|
+
date_filter=_resolve_tab_date_filter(payload["tabId"]),
|
|
667
735
|
is_untagged_view=payload["isUntaggedView"], from_root_index=payload["fromRootIndex"],
|
|
668
736
|
direction=payload["direction"],
|
|
669
737
|
)
|
|
@@ -737,6 +805,15 @@ def tag_suggestions(payload: TagSuggestionsRequest) -> Dict[str, object]:
|
|
|
737
805
|
|
|
738
806
|
_require_note_present(note_id, context="notes.tag-suggestions")
|
|
739
807
|
|
|
808
|
+
# Typing after a tag's colon (jogging:mi, drug:dosage=10m): property names or units.
|
|
809
|
+
if has_property_syntax(prefix):
|
|
810
|
+
return _property_suggestions_response(
|
|
811
|
+
search_index.suggest_property_completions(
|
|
812
|
+
typed=prefix, place=PROPERTY_SUGGESTIONS_IN_TAG_BAR, limit=MAX_TAG_SUGGESTIONS,
|
|
813
|
+
),
|
|
814
|
+
personalized=False,
|
|
815
|
+
)
|
|
816
|
+
|
|
740
817
|
suggestions = suggest_tags_with_reasons_for_note(
|
|
741
818
|
note_id=note_id,
|
|
742
819
|
anchors=anchors,
|
|
@@ -749,6 +826,7 @@ def tag_suggestions(payload: TagSuggestionsRequest) -> Dict[str, object]:
|
|
|
749
826
|
return {
|
|
750
827
|
"suggestions": [suggestion.tag for suggestion in suggestions],
|
|
751
828
|
"reasons": {suggestion.tag: list(suggestion.reasons) for suggestion in suggestions},
|
|
829
|
+
"labels": {suggestion.tag: suggestion.tag for suggestion in suggestions},
|
|
752
830
|
}
|
|
753
831
|
|
|
754
832
|
|
|
@@ -797,6 +875,7 @@ def export_summary(request: Request) -> Dict[str, object]:
|
|
|
797
875
|
normalized_search = None
|
|
798
876
|
counts = exported_credential_counts(
|
|
799
877
|
search=normalized_search, sort_mode=_resolve_tab_sort_mode(tab_id),
|
|
878
|
+
date_filter=_resolve_tab_date_filter(tab_id),
|
|
800
879
|
is_untagged_view=is_untagged_view == "true", root_note_id=note_id,
|
|
801
880
|
)
|
|
802
881
|
return {
|
|
@@ -856,6 +935,7 @@ def export_notes_html(request: Request) -> Response:
|
|
|
856
935
|
document = build_notes_export_document(
|
|
857
936
|
search=normalized_search,
|
|
858
937
|
sort_mode=_resolve_tab_sort_mode(tab_id),
|
|
938
|
+
date_filter=_resolve_tab_date_filter(tab_id),
|
|
859
939
|
is_untagged_view=is_untagged_view == "true",
|
|
860
940
|
theme=normalized_theme,
|
|
861
941
|
token=token,
|
|
@@ -917,6 +997,7 @@ def backlinks(request: Request, note_id: str) -> Dict[str, object]:
|
|
|
917
997
|
search=normalized_search,
|
|
918
998
|
editing_note_id=None,
|
|
919
999
|
sort_mode="normal",
|
|
1000
|
+
date_filter=None,
|
|
920
1001
|
ordered_root_ids=None,
|
|
921
1002
|
)
|
|
922
1003
|
source_note_ids = search_scope.allowed_note_ids
|
|
@@ -1117,6 +1198,7 @@ def _robot_scope_note_ids(body: dict) -> frozenset[str]:
|
|
|
1117
1198
|
return resolve_view_scope_membership(
|
|
1118
1199
|
search=body["search"],
|
|
1119
1200
|
sort_mode=_resolve_tab_sort_mode(body["tabId"]),
|
|
1201
|
+
date_filter=_resolve_tab_date_filter(body["tabId"]),
|
|
1120
1202
|
is_untagged_view=body["isUntaggedView"],
|
|
1121
1203
|
).allowed_note_ids
|
|
1122
1204
|
|
|
@@ -21,7 +21,8 @@ from app.services.tag_term_matching import list_significant_content_match_segmen
|
|
|
21
21
|
from app.utils.not_found import NOT_FOUND
|
|
22
22
|
from app.services.note_store import store as note_store
|
|
23
23
|
from app.services.sync import generate_new_uuid
|
|
24
|
-
from app.services.
|
|
24
|
+
from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_RULE, is_property_term
|
|
25
|
+
from app.services.tag_ontology import PropertyAtom, RegexAtom, TagAtom, TextAtom, parse_rules_text, rule_text_tests_values
|
|
25
26
|
from app.services.ontology_rules_store import (
|
|
26
27
|
build_direct_edge_rule_map,
|
|
27
28
|
create_rule_line,
|
|
@@ -97,6 +98,10 @@ def _collect_candidate_note_ids_for_rules(rules: list) -> set[str]:
|
|
|
97
98
|
tags: list[str] = []
|
|
98
99
|
phrases: list[str] = []
|
|
99
100
|
regexes: list[re.Pattern[str]] = []
|
|
101
|
+
# A rule testing super tag values changes notes' own tags: _refresh_note_tags
|
|
102
|
+
# rebuilds every note's, so it needs no candidates.
|
|
103
|
+
if any(isinstance(atom, PropertyAtom) for atom in rule.lhs):
|
|
104
|
+
continue
|
|
100
105
|
for atom in rule.lhs:
|
|
101
106
|
if isinstance(atom, TagAtom):
|
|
102
107
|
tags.append(atom.tag)
|
|
@@ -133,6 +138,32 @@ def _collect_candidate_note_ids_for_rules(rules: list) -> set[str]:
|
|
|
133
138
|
return candidates
|
|
134
139
|
|
|
135
140
|
|
|
141
|
+
def _rule_warnings(text: str) -> list[str]:
|
|
142
|
+
"""What looks wrong in a saved rule: a super tag term no note can match, most likely
|
|
143
|
+
a typo (jogging:mile>10 where notes say miles)."""
|
|
144
|
+
warnings: list[str] = []
|
|
145
|
+
for rule in parse_rules_text(text=f"{text}\n", filename="ontology_rules:warnings"):
|
|
146
|
+
for atom in rule.lhs:
|
|
147
|
+
if not isinstance(atom, PropertyAtom):
|
|
148
|
+
continue
|
|
149
|
+
condition = atom.condition
|
|
150
|
+
if search_index.uses_property(tag=condition.tag, property_name=condition.name):
|
|
151
|
+
continue
|
|
152
|
+
warnings.append(f"No note has {condition.tag}:{condition.name} yet; check the spelling.")
|
|
153
|
+
return warnings
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _refresh_note_tags(candidate_note_ids: set[str], *, rule_texts: list[str]) -> None:
|
|
157
|
+
"""After a rule changed: the candidate notes' tags. A rule testing super tag values
|
|
158
|
+
refreshes the notes it can concern, with their children and the notes referencing
|
|
159
|
+
them, since the tags it gives pass to those (NoteStore.refresh_tags_for_value_rules)."""
|
|
160
|
+
if any(rule_text_tests_values(text) for text in rule_texts):
|
|
161
|
+
note_store.refresh_tags_for_value_rules(rule_texts=[text for text in rule_texts if rule_text_tests_values(text)])
|
|
162
|
+
if all(rule_text_tests_values(text) for text in rule_texts):
|
|
163
|
+
return
|
|
164
|
+
note_store.rebuild_search_index_tag_terms_for_notes(candidate_note_ids)
|
|
165
|
+
|
|
166
|
+
|
|
136
167
|
def _collect_candidate_note_ids_for_texts(texts: list[str], *, filename: str) -> set[str]:
|
|
137
168
|
candidates: set[str] = set()
|
|
138
169
|
for text in texts:
|
|
@@ -181,10 +212,10 @@ def create_rule(request: Request, payload: RuleTextRequest) -> dict:
|
|
|
181
212
|
token = _maybe_bearer_token(request)
|
|
182
213
|
rule_id, normalized = create_rule_line(text=text, token=token)
|
|
183
214
|
if note_store.loaded:
|
|
184
|
-
|
|
215
|
+
_refresh_note_tags(candidate_note_ids, rule_texts=[text])
|
|
185
216
|
update_uuid = generate_new_uuid()
|
|
186
|
-
return {"id": rule_id, "text": normalized, "updateUUID": update_uuid}
|
|
187
|
-
return {"id": rule_id, "text": normalized}
|
|
217
|
+
return {"id": rule_id, "text": normalized, "updateUUID": update_uuid, "warnings": _rule_warnings(normalized)}
|
|
218
|
+
return {"id": rule_id, "text": normalized, "warnings": []}
|
|
188
219
|
|
|
189
220
|
|
|
190
221
|
@router.put("/rules/{rule_id}")
|
|
@@ -210,18 +241,19 @@ def update_rule(request: Request, rule_id: int, payload: RuleTextRequest) -> dic
|
|
|
210
241
|
break
|
|
211
242
|
if old_text is None:
|
|
212
243
|
raise RuntimeError("Expected rule text for update")
|
|
244
|
+
rule_texts = [old_text, text]
|
|
213
245
|
candidate_note_ids = _collect_candidate_note_ids_for_texts(
|
|
214
|
-
|
|
246
|
+
rule_texts,
|
|
215
247
|
filename=f"ontology_rules:{rule_id}",
|
|
216
248
|
)
|
|
217
249
|
|
|
218
250
|
token = _maybe_bearer_token(request)
|
|
219
251
|
updated_id, normalized = update_rule_line(rule_id=rule_id, text=text, token=token)
|
|
220
252
|
if note_store.loaded:
|
|
221
|
-
|
|
253
|
+
_refresh_note_tags(candidate_note_ids, rule_texts=rule_texts)
|
|
222
254
|
update_uuid = generate_new_uuid()
|
|
223
|
-
return {"id": updated_id, "text": normalized, "updateUUID": update_uuid}
|
|
224
|
-
return {"id": updated_id, "text": normalized}
|
|
255
|
+
return {"id": updated_id, "text": normalized, "updateUUID": update_uuid, "warnings": _rule_warnings(normalized)}
|
|
256
|
+
return {"id": updated_id, "text": normalized, "warnings": []}
|
|
225
257
|
|
|
226
258
|
|
|
227
259
|
@router.delete("/rules/{rule_id}")
|
|
@@ -241,14 +273,15 @@ def delete_rule(rule_id: int) -> dict:
|
|
|
241
273
|
break
|
|
242
274
|
if old_text is None:
|
|
243
275
|
raise RuntimeError("Expected rule text for delete")
|
|
276
|
+
rule_texts = [old_text]
|
|
244
277
|
candidate_note_ids = _collect_candidate_note_ids_for_texts(
|
|
245
|
-
|
|
278
|
+
rule_texts,
|
|
246
279
|
filename=f"ontology_rules:{rule_id}",
|
|
247
280
|
)
|
|
248
281
|
|
|
249
282
|
delete_rule_line(rule_id=rule_id)
|
|
250
283
|
if note_store.loaded:
|
|
251
|
-
|
|
284
|
+
_refresh_note_tags(candidate_note_ids, rule_texts=rule_texts)
|
|
252
285
|
update_uuid = generate_new_uuid()
|
|
253
286
|
return {"ok": True, "updateUUID": update_uuid}
|
|
254
287
|
return {"ok": True}
|
|
@@ -306,6 +339,8 @@ def focus_view(tag: str) -> dict:
|
|
|
306
339
|
return "text", f'"{escaped}"'
|
|
307
340
|
if isinstance(atom, RegexAtom):
|
|
308
341
|
return "regex", f"/{atom.pattern}/{atom.flags}"
|
|
342
|
+
if isinstance(atom, PropertyAtom):
|
|
343
|
+
return "value", atom.condition.format()
|
|
309
344
|
raise TypeError(f"Unknown atom: {type(atom)}")
|
|
310
345
|
|
|
311
346
|
def atom_payload(atom: object) -> dict:
|
|
@@ -316,6 +351,10 @@ def focus_view(tag: str) -> dict:
|
|
|
316
351
|
return {"kind": kind, "text": display}
|
|
317
352
|
if kind == "regex":
|
|
318
353
|
return {"kind": kind, "regex": display}
|
|
354
|
+
if kind == "value":
|
|
355
|
+
# A super tag term: its tag is a chip like any tag, the rest is shown as written.
|
|
356
|
+
assert isinstance(atom, PropertyAtom)
|
|
357
|
+
return {"kind": kind, "value": display, "tag": atom.condition.tag}
|
|
319
358
|
raise RuntimeError(f"Unexpected atom kind: {kind}")
|
|
320
359
|
|
|
321
360
|
def format_atom_for_edit(atom: object) -> str:
|
|
@@ -327,6 +366,8 @@ def focus_view(tag: str) -> dict:
|
|
|
327
366
|
if isinstance(atom, RegexAtom):
|
|
328
367
|
escaped = atom.pattern.replace("\\", "\\\\").replace("/", "\\/")
|
|
329
368
|
return f"/{escaped}/{atom.flags}"
|
|
369
|
+
if isinstance(atom, PropertyAtom):
|
|
370
|
+
return atom.condition.format()
|
|
330
371
|
raise TypeError(f"Unknown atom: {type(atom)}")
|
|
331
372
|
|
|
332
373
|
def record_equality_rule_ids(rules: list, rule_id: int) -> bool:
|
|
@@ -555,6 +596,18 @@ def list_tags(q: str, limit: int, focus: str, relation: str) -> dict:
|
|
|
555
596
|
if (relation == "none") != (focus == ""):
|
|
556
597
|
raise ValueError("A focus tag goes with a relation, and only with one")
|
|
557
598
|
|
|
599
|
+
# A super tag term in an incoming condition (jogging:mi, drug:dosage>5): its property
|
|
600
|
+
# names, units and values, as a rule reads them (docs/design/tag-properties.md).
|
|
601
|
+
if relation == "incoming" and is_property_term(q):
|
|
602
|
+
suggestions = search_index.suggest_property_completions(typed=q, place=PROPERTY_SUGGESTIONS_IN_RULE, limit=limit)
|
|
603
|
+
return {
|
|
604
|
+
"totalCount": len(suggestions),
|
|
605
|
+
"tags": [
|
|
606
|
+
{"tag": suggestion.replacement, "count": suggestion.note_count, "label": suggestion.label}
|
|
607
|
+
for suggestion in suggestions
|
|
608
|
+
],
|
|
609
|
+
}
|
|
610
|
+
|
|
558
611
|
ontology = get_ontology()
|
|
559
612
|
# A tag only the rules name is on no note yet.
|
|
560
613
|
tag_counts = {tag: 0 for tag in extract_ontology_tags(ontology)}
|
|
@@ -568,12 +621,12 @@ def list_tags(q: str, limit: int, focus: str, relation: str) -> dict:
|
|
|
568
621
|
ordered.extend(tag for tag in group if needle == "" or _match_rank(needle=needle, tag=tag) != NOT_FOUND)
|
|
569
622
|
rest = [(_match_rank(needle=needle, tag=tag), index, tag) for index, tag in enumerate(order.by_use)]
|
|
570
623
|
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]]
|
|
624
|
+
payload = [{"tag": tag, "count": tag_counts[tag], "label": tag} for tag in ordered[:limit]]
|
|
572
625
|
return {"totalCount": len(tag_counts), "tags": payload}
|
|
573
626
|
|
|
574
627
|
if needle == "":
|
|
575
628
|
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]}
|
|
629
|
+
return {"totalCount": len(tag_counts), "tags": [{"tag": tag, "count": tag_counts[tag], "label": tag} for tag in ordered]}
|
|
577
630
|
|
|
578
631
|
matches: list[tuple[int, int, str]] = []
|
|
579
632
|
for tag in tag_counts:
|
|
@@ -582,5 +635,5 @@ def list_tags(q: str, limit: int, focus: str, relation: str) -> dict:
|
|
|
582
635
|
matches.append((rank, -tag_counts[tag], tag))
|
|
583
636
|
# By rank, then most used, then name.
|
|
584
637
|
matches.sort()
|
|
585
|
-
payload = [{"tag": tag, "count": tag_counts[tag]} for _rank, _negative_count, tag in matches[:limit]]
|
|
638
|
+
payload = [{"tag": tag, "count": tag_counts[tag], "label": tag} for _rank, _negative_count, tag in matches[:limit]]
|
|
586
639
|
return {"totalCount": len(tag_counts), "tags": payload}
|
|
@@ -14,7 +14,9 @@ from app.services.search_index import search_index
|
|
|
14
14
|
from app.services.tag_case import build_preferred_tag_case_map
|
|
15
15
|
from app.services.search_query import ParsedSearchQuery, SearchClause
|
|
16
16
|
from app.services.search_query import format_search_query, format_search_term, parse_search_query
|
|
17
|
+
from app.services.search_index import extract_ordered_tags_for_agent
|
|
17
18
|
from app.services.tag_ontology import is_valid_tag_token
|
|
19
|
+
from app.services.tag_properties import PROPERTY_SEPARATOR, has_property_syntax, split_property_segments, tag_part_of_token
|
|
18
20
|
from app.services.content_formatting import extract_note_text_for_agent
|
|
19
21
|
|
|
20
22
|
|
|
@@ -106,6 +108,37 @@ def visible_tag_counts(boundary: CloudPrivacyBoundary) -> tuple[dict[str, str],
|
|
|
106
108
|
return display, counts
|
|
107
109
|
|
|
108
110
|
|
|
111
|
+
# The AI is shown at most this many properties in use (visible_super_tag_examples).
|
|
112
|
+
_MAX_SUPER_TAG_EXAMPLES = 40
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def visible_super_tag_examples(boundary: CloudPrivacyBoundary) -> tuple[str, ...]:
|
|
116
|
+
"""One example of each property in use on notes the AI may see, most used first
|
|
117
|
+
(jogging:miles=3, drug:dosage=10mg), so super tags it proposes reuse their names and
|
|
118
|
+
units (docs/design/tag-properties.md)."""
|
|
119
|
+
note_ids = tuple(note_store.list_note_ids())
|
|
120
|
+
hidden = cloud_privacy_evaluator.hidden_note_ids(note_ids=note_ids, boundary=boundary)
|
|
121
|
+
counts: Counter[tuple[str, str]] = Counter()
|
|
122
|
+
examples: dict[tuple[str, str], str] = {}
|
|
123
|
+
for note_id in note_ids:
|
|
124
|
+
tags = note_store.get_note(note_id).tags
|
|
125
|
+
if note_id in hidden or PROPERTY_SEPARATOR not in tags:
|
|
126
|
+
continue
|
|
127
|
+
for token in extract_ordered_tags_for_agent(tags):
|
|
128
|
+
if not has_property_syntax(token):
|
|
129
|
+
continue
|
|
130
|
+
tag = tag_part_of_token(token).split("=", 1)[0]
|
|
131
|
+
for segment in split_property_segments(token[len(tag_part_of_token(token)) + 1:]):
|
|
132
|
+
name, has_value, value = segment.partition("=")
|
|
133
|
+
if not has_value or value == "":
|
|
134
|
+
continue
|
|
135
|
+
key = (tag.casefold(), name.casefold())
|
|
136
|
+
counts[key] += 1
|
|
137
|
+
if key not in examples:
|
|
138
|
+
examples[key] = f"{tag}{PROPERTY_SEPARATOR}{name}={value}"
|
|
139
|
+
return tuple(examples[key] for key, _count in counts.most_common(_MAX_SUPER_TAG_EXAMPLES))
|
|
140
|
+
|
|
141
|
+
|
|
109
142
|
# What the AI is shown in place of a search term it may not see.
|
|
110
143
|
PRIVATE_SEARCH_TERM = "[private]"
|
|
111
144
|
|
|
@@ -135,6 +168,7 @@ def _disclosable_clause_terms(
|
|
|
135
168
|
"""The clause's terms as the AI may be shown them, and whether any was withheld."""
|
|
136
169
|
required_terms = [format_search_term(tag, is_phrase=False, is_excluded=False) for tag in sorted(clause.required_tags)]
|
|
137
170
|
required_terms += [format_search_term(phrase, is_phrase=True, is_excluded=False) for phrase in clause.required_text]
|
|
171
|
+
required_terms += [condition.format() for condition in clause.required_properties]
|
|
138
172
|
shown: list[str] = []
|
|
139
173
|
withheld = False
|
|
140
174
|
# Every required term picks out the same notes: the ones the clause finds.
|
|
@@ -148,7 +182,9 @@ def _disclosable_clause_terms(
|
|
|
148
182
|
for tag in sorted(clause.forbidden_tags):
|
|
149
183
|
removed = SearchClause(required_tags=clause.required_tags | {tag},
|
|
150
184
|
forbidden_tags=clause.forbidden_tags - {tag},
|
|
151
|
-
required_text=clause.required_text, forbidden_text=clause.forbidden_text
|
|
185
|
+
required_text=clause.required_text, forbidden_text=clause.forbidden_text,
|
|
186
|
+
required_properties=clause.required_properties,
|
|
187
|
+
forbidden_properties=clause.forbidden_properties)
|
|
152
188
|
if finds_visible_note(_clause_search(removed)):
|
|
153
189
|
shown.append(format_search_term(tag, is_phrase=False, is_excluded=True))
|
|
154
190
|
else:
|
|
@@ -156,11 +192,23 @@ def _disclosable_clause_terms(
|
|
|
156
192
|
for index, phrase in enumerate(clause.forbidden_text):
|
|
157
193
|
removed = SearchClause(required_tags=clause.required_tags, forbidden_tags=clause.forbidden_tags,
|
|
158
194
|
required_text=clause.required_text + (phrase,),
|
|
159
|
-
forbidden_text=clause.forbidden_text[:index] + clause.forbidden_text[index + 1:]
|
|
195
|
+
forbidden_text=clause.forbidden_text[:index] + clause.forbidden_text[index + 1:],
|
|
196
|
+
required_properties=clause.required_properties,
|
|
197
|
+
forbidden_properties=clause.forbidden_properties)
|
|
160
198
|
if finds_visible_note(_clause_search(removed)):
|
|
161
199
|
shown.append(format_search_term(phrase, is_phrase=True, is_excluded=True))
|
|
162
200
|
else:
|
|
163
201
|
excluded_withheld = True
|
|
202
|
+
for index, condition in enumerate(clause.forbidden_properties):
|
|
203
|
+
removed = SearchClause(required_tags=clause.required_tags, forbidden_tags=clause.forbidden_tags,
|
|
204
|
+
required_text=clause.required_text, forbidden_text=clause.forbidden_text,
|
|
205
|
+
required_properties=clause.required_properties + (condition,),
|
|
206
|
+
forbidden_properties=clause.forbidden_properties[:index]
|
|
207
|
+
+ clause.forbidden_properties[index + 1:])
|
|
208
|
+
if finds_visible_note(_clause_search(removed)):
|
|
209
|
+
shown.append(f"-{condition.format()}")
|
|
210
|
+
else:
|
|
211
|
+
excluded_withheld = True
|
|
164
212
|
if excluded_withheld:
|
|
165
213
|
shown.append(f"-{PRIVATE_SEARCH_TERM}")
|
|
166
214
|
return shown, withheld or excluded_withheld
|
|
@@ -26,7 +26,7 @@ from dataclasses import dataclass
|
|
|
26
26
|
|
|
27
27
|
from app.services.agent.cloud_privacy import CloudPrivacyBoundary
|
|
28
28
|
from app.services.agent.cloud_privacy import cloud_privacy_evaluator
|
|
29
|
-
from app.services.agent.cloud_privacy import visible_tag_counts
|
|
29
|
+
from app.services.agent.cloud_privacy import visible_super_tag_examples, visible_tag_counts
|
|
30
30
|
from app.services.agent.inference import InferenceAdapter
|
|
31
31
|
from app.services.agent.skill_settings import AgentSkill
|
|
32
32
|
from app.services.agent.tagging import TagBatch
|
|
@@ -37,7 +37,8 @@ from app.services.agent.token_estimation import estimate_input_tokens
|
|
|
37
37
|
from app.services.agent.web_settings import AgentWebSettings
|
|
38
38
|
from app.services.content_formatting import extract_note_text_for_agent
|
|
39
39
|
from app.services.note_store import store as note_store
|
|
40
|
-
from app.services.search_index import extract_ordered_tags_for_search
|
|
40
|
+
from app.services.search_index import extract_ordered_tags_for_agent, extract_ordered_tags_for_search
|
|
41
|
+
from app.services.tag_properties import tag_part_of_token
|
|
41
42
|
from app.services.search_index import search_index
|
|
42
43
|
from app.services.tag_suggestions import suggest_tags_for_note
|
|
43
44
|
from app.contracts import preserves, produces, requires
|
|
@@ -88,6 +89,8 @@ class NoteTagRequest:
|
|
|
88
89
|
tag_skill: AgentSkill
|
|
89
90
|
# The tags on notes the AI may see (cloud_privacy.visible_tag_counts).
|
|
90
91
|
visible_vocabulary: dict[str, str]
|
|
92
|
+
# One example of each property in use there (cloud_privacy.visible_super_tag_examples).
|
|
93
|
+
super_tag_examples: tuple[str, ...]
|
|
91
94
|
|
|
92
95
|
|
|
93
96
|
@dataclass(frozen=True, slots=True)
|
|
@@ -123,7 +126,7 @@ def _note_text(note_id: str) -> dict[str, object]:
|
|
|
123
126
|
record = note_store.get_note(note_id)
|
|
124
127
|
content, redacted = extract_note_text_for_agent(content_html=record.content, tags=record.tags)
|
|
125
128
|
assert not redacted, "A note the AI may see is never password protected"
|
|
126
|
-
return {"content_text": content, "tags": list(
|
|
129
|
+
return {"content_text": content, "tags": list(extract_ordered_tags_for_agent(record.tags))}
|
|
127
130
|
|
|
128
131
|
|
|
129
132
|
def _note_node(note_id: str) -> dict[str, object]:
|
|
@@ -212,6 +215,7 @@ def build_note_tag_request(
|
|
|
212
215
|
ancestors_by_batch=tuple(context for _trees, context in groups),
|
|
213
216
|
vocabulary=vocabulary, rules=rules, tag_skill=tag_skill,
|
|
214
217
|
visible_vocabulary=visible_tag_counts(boundary)[0],
|
|
218
|
+
super_tag_examples=visible_super_tag_examples(boundary),
|
|
215
219
|
), "cloud_disclosable")
|
|
216
220
|
|
|
217
221
|
|
|
@@ -226,6 +230,7 @@ def request_messages(request: NoteTagRequest, index: int, prior_batch_new_tags:
|
|
|
226
230
|
"accepted_vocabulary": [tag for tag, _count in request.vocabulary],
|
|
227
231
|
"accepted_vocabulary_note_counts": [count for _tag, count in request.vocabulary],
|
|
228
232
|
"prior_batch_new_tags": list(prior_batch_new_tags),
|
|
233
|
+
"super_tag_properties": list(request.super_tag_examples),
|
|
229
234
|
}
|
|
230
235
|
messages = tag_batch_messages(
|
|
231
236
|
tag_skill=request.tag_skill, vocabulary_scope=_VOCABULARY_SCOPE, focus="both", user_payload=user_payload,
|
|
@@ -240,7 +245,8 @@ def keep_new_tags_up_to_limit(*, tags: tuple[str, ...], visible_vocabulary: dict
|
|
|
240
245
|
kept = []
|
|
241
246
|
new_count = 0
|
|
242
247
|
for tag in tags:
|
|
243
|
-
|
|
248
|
+
# A super tag is new when its tag is (jogging:miles=3 on an existing jogging is not).
|
|
249
|
+
if tag_part_of_token(tag).casefold() not in visible_vocabulary:
|
|
244
250
|
if new_count == MAX_NEW_TAGS:
|
|
245
251
|
continue
|
|
246
252
|
new_count += 1
|