MetaList 0.12.0__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metalist-0.12.0/metalist.egg-info → metalist-0.14.0}/PKG-INFO +19 -1
- {metalist-0.12.0 → metalist-0.14.0}/README.md +17 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/middleware/auth.py +1 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/note_requests.py +20 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/ai.py +4 -2
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/auth.py +6 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/notes.py +67 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/config.py +0 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/encryption_audit.py +16 -9
- {metalist-0.12.0 → metalist-0.14.0}/app/exception_boundaries.py +8 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/main.py +5 -3
- metalist-0.14.0/app/presentation/login_page.py +18 -0
- metalist-0.14.0/app/services/agent/action_log.py +59 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/agent_loop.py +16 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/context.py +18 -2
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/help_catalog.py +1 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/prompts/agent.md +7 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/runtime.py +6 -2
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-ai.md +1 -1
- metalist-0.14.0/app/services/agent/skills/help-dictation.md +94 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-formatting.md +6 -3
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-menus.md +2 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-notes.md +1 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-privacy.md +8 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-references.md +4 -3
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-releases.md +17 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-search.md +18 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-tags.md +3 -2
- {metalist-0.12.0 → metalist-0.14.0}/app/services/ai_chat.py +37 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/ai_chat_stream.py +8 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/services/backlink_index.py +1 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/services/client_state_service.py +10 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/content_formatting.py +11 -5
- metalist-0.14.0/app/services/dictation_cleanup.py +469 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/embedded_references.py +28 -61
- metalist-0.14.0/app/services/file_text_preview.py +83 -0
- metalist-0.14.0/app/services/link_title_retry.py +169 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/link_titles.py +389 -5
- {metalist-0.12.0 → metalist-0.14.0}/app/services/note_store.py +15 -6
- {metalist-0.12.0 → metalist-0.14.0}/app/services/reference_presentation.py +1 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/services/search_index.py +69 -14
- {metalist-0.12.0 → metalist-0.14.0}/app/services/search_query.py +5 -1
- metalist-0.14.0/app/services/search_text.py +141 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/tab_state.py +20 -6
- {metalist-0.12.0 → metalist-0.14.0}/app/services/tag_suggestions.py +104 -23
- metalist-0.14.0/app/startup_console.py +100 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/config/agent-menu-actions.json +12 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/config/command_palette_tags.json +8 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/css/main.css +247 -183
- metalist-0.14.0/app/static/js/locked.js +36 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/main.js +0 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +4 -2
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/proposal-menu.js +5 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/api-client.js +21 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/auth.js +162 -284
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/command-palette-controller.js +78 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/endpoint-registry.js +15 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/preferences-store.js +38 -23
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/config.js +4 -10
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/ai-agent-settings-modal.js +4 -0
- metalist-0.14.0/app/static/js/modules/modals/dictation-settings-modal.js +130 -0
- metalist-0.14.0/app/static/js/modules/modals/link-title-retry-modal.js +308 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/ontology-modal.js +20 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/prioritize-modal.js +3 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/visual-cues-modal.js +1 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/input-events.js +14 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/keyboard-events.js +23 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/search-events.js +7 -0
- metalist-0.14.0/app/static/js/modules/mode-manager/services/dictation-note-paste.js +48 -0
- metalist-0.14.0/app/static/js/modules/mode-manager/services/dictation-paste-padding.js +21 -0
- metalist-0.14.0/app/static/js/modules/mode-manager/services/dictation-paste-service.js +245 -0
- metalist-0.14.0/app/static/js/modules/mode-manager/services/dropped-file-preview-service.js +47 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +9 -1
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-syntax-service.js +52 -0
- metalist-0.14.0/app/templates/_logo_mark.html +6 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/templates/base.html +0 -5
- {metalist-0.12.0 → metalist-0.14.0}/app/templates/index.html +37 -51
- metalist-0.14.0/app/templates/locked.html +37 -0
- metalist-0.14.0/app/usecases/create_file_preview_child.py +68 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/search_comment_autofill.py +4 -3
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/search_context_tags.py +4 -3
- {metalist-0.12.0 → metalist-0.14.0}/app/utils/text_utils.py +42 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/version.py +1 -1
- {metalist-0.12.0 → metalist-0.14.0}/main.py +57 -25
- {metalist-0.12.0 → metalist-0.14.0/metalist.egg-info}/PKG-INFO +19 -1
- {metalist-0.12.0 → metalist-0.14.0}/metalist.egg-info/SOURCES.txt +15 -1
- {metalist-0.12.0 → metalist-0.14.0}/metalist.egg-info/requires.txt +1 -0
- {metalist-0.12.0 → metalist-0.14.0}/pyproject.toml +1 -0
- metalist-0.12.0/app/services/search_text.py +0 -65
- metalist-0.12.0/app/static/js/locked.js +0 -14
- metalist-0.12.0/app/static/video/login-startup.mp4 +0 -0
- metalist-0.12.0/app/templates/locked.html +0 -85
- {metalist-0.12.0 → metalist-0.14.0}/MANIFEST.in +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/deps.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/dev.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/request_auth.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/app_updates.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/backups.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/files.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/ontology.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/reminders.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/remote_images.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/routes/test.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/transactions.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/api/upload_limits.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/data_directory.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/editable_files_migration.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/engine.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/file_schema.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/file_session.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/files_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/link_titles_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/live_recovery.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/migrations.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/notes_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/reminders_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/retire_sounds.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/schema.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/search_history_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/session.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/settings_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/tab_state_sql.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/db/version.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/https_proxy.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/commands.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/database.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/entities.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/enums.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/linked_list.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/list_operations.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/list_traversal.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/note_crud.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/models/utils.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/network_settings.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/presentation/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/presentation/render/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/presentation/templates.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/authenticated_logging.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/encryption.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/http_error_diagnostics.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/http_headers.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/note_html.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/request_boundary.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/request_hosts.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/sensitive_cache.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/sensitive_logging.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/shell_execution.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/security/validation_errors.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/server_runtime.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/agent_tools.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/citation_tokens.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/cloud_privacy.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/evidence_serialization.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/execution_errors.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/failure_explanations.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/history.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/inference.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/investigation.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/judging.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/menu_actions.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/model_policy.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/note_aliases.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/openai_cost_tracking.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/openai_inference.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/prompt_settings.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/prompts/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/prompts/final-response.md +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/prompts/system.md +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/release_notes.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/retrieval_settings.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/scope.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skill_settings.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-data.md +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/help-reminders.md +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/staged-summary.md +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/tag-proposals.md +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/skills/web-browsing.md +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/staged_summary.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/structured_inference.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/tagging.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/tagging_run.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/token_estimation.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/tool_calling.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/trace.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/web_actions.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/web_capabilities.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/web_evidence.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/web_fetch.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/agent/web_settings.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/ai_chat_rendering.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/app_update_worker.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/app_updates.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/auth.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/auth_cache_state.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/auth_service.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/backlinks.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/backup_service.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/backup_settings_service.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/bulk_operation.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/content_cache.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/diagnostics.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/encryption.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/exception_capture.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/file_edit_sessions.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/file_registry.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/file_storage.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/footnote_layout.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/footnote_rendering.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/hierarchy.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/html_export.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/html_unformatting.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/hydration_state.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/image_size_formatting.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/inline_image_dimensions.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/inline_image_occurrences.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/input_errors.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/integrity.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/latex_rendering.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/login_rate_limit.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/maintenance_mode.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/markdown_rendering.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/namespace_deletion_worker.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/namespace_rename_worker.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/namespace_runtime_guard.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/namespace_switcher.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/note_fullscreen.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/note_image_tags.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/note_ordering.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/ontology_rules_store.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/openai_credentials.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/password_note_fields.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/public_http.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/reminders.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/remote_image_proxy.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/request_recovery.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/resource_limits.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/root_sorting.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/runtime_generation.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/runtime_hardening.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/runtime_lock.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/search_history.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/search_history_storage.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/selected_text_tag.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/self_update.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/session_timeout_service.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/shell_session_service.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/snapshot.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/store.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/structured_note_renderers.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/sync.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/sync_state.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/tag_case.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/tag_ontology.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/tag_rename.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/tag_term_matching.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/test_reset.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/tokens.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/undo_state.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/update_backups.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/update_installer.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/update_preflight.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/view_cache.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/view_diff.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/view_state.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/services/windows_process_control.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/startup_environment.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/startup_js_sanity.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/startup_sanity.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/startup_sanity_config.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/css/floating-notes.css +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/css/forms.css +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/img/favicon.ico +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/agent-web-settings.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-message-placement.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/bulk-scope-question.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/confirmation-card.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/confirmation-question.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/ai-chat/summary-batch-preview.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/api-error-diagnostics.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/api-failure-classification-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/app-update-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/application-state.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/connectivity-monitor.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/dom-utils-fixed.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/elapsed-time.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-autosave.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-editor-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-editor-state.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-loader.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-preview-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/excalidraw/excalidraw-scene.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/expected-errors.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/login-namespace-picker.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/maintenance.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-result-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/base-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/confirmation-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/help-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-modals.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/password-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/modals/version-info-modal.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/context-menu-events.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/events/mouse-events.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/mode-context.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-drag-indicator-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-note-creation-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/mode-manager/services/viewport-hold-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/note-html-sanitizer.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/password-operation-response.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/password-policy.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/password-strength.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/selection-markers.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/namespace-deleted.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/namespace-renamed.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/dompurify-3.4.16.LICENSE.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/dompurify-3.4.16.min.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/excalidraw.css +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Bold.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Medium.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Regular.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Virgil/Virgil-Regular.woff2 +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1.LICENSE.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/excalidraw-0.18.1.min.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/markdown-it-14.3.2.LICENSE.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/markdown-it-14.3.2.min.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/static/note-html-policy.json +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/templates/maintenance.html +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/templates/namespace_deleted.html +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/templates/namespace_renamed.html +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/templates/notes_list.html +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/upload_limits.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/add_selected_text_tag.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/base.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/bulk_tag_proposals.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/collapse.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/copy_note.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/create_child.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/create_note.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/create_sibling.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/delete_tag.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/expand.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/file_edit_session.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/indent.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/lock.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/move.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/move_to_top.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/outdent.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/paste_child.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/prefetch_link_titles.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/prioritize.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/redo.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/rename_tag.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/resize_image.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/run_shell.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/split_note.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/tag_proposals.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/toggle_reference_mode.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/undo.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/unformat_content.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/update_content.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/usecases/view.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/utils/__init__.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/app/utils/encryption.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/convert-from-legacy.py +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.12.0 → metalist-0.14.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metalist
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
|
|
5
5
|
Project-URL: Homepage, https://github.com/evolvingstuff/metalist
|
|
6
6
|
Project-URL: Repository, https://github.com/evolvingstuff/metalist
|
|
@@ -23,6 +23,7 @@ Requires-Dist: pydantic==2.13.4
|
|
|
23
23
|
Requires-Dist: pypdf==6.19.0
|
|
24
24
|
Requires-Dist: python-dotenv==1.2.2
|
|
25
25
|
Requires-Dist: python-multipart==0.0.32
|
|
26
|
+
Requires-Dist: rich==14.3.4
|
|
26
27
|
Requires-Dist: starlette==1.3.1
|
|
27
28
|
Requires-Dist: tqdm==4.70.0
|
|
28
29
|
Requires-Dist: tree-sitter==0.25.2
|
|
@@ -49,6 +50,23 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
49
50
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
50
51
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
51
52
|
|
|
53
|
+
## Changes in 0.14.0
|
|
54
|
+
|
|
55
|
+
- A new login screen: one dark screen with the MetaList logo. The namespace, password and OK fade in together; once the password is accepted, the loading progress slides in with the current step and the seconds elapsed. When the first login after an update backs up and upgrades the namespace, a note under OK says so. The Session locked page has the same look, and there is no white flash between them.
|
|
56
|
+
- Web link titles: links to Reddit (including share links), YouTube, Vimeo, TikTok, Spotify and SoundCloud get their real titles. Lookups are paced per site, so a note full of links no longer trips a site's rate limit. Login, consent and site-name-only titles ("Sign in", "Reddit") show the link instead. The new command palette action Retry failed link titles asks every failed link again, with a progress dialog.
|
|
57
|
+
- Quoted search also matches link titles and the URLs hidden behind link labels, and the AI sees those URLs too. Pasting into a quoted search inserts the text as copied.
|
|
58
|
+
- `[[note id]]` is always a link, even in a note with a `[[ ]]` formatting tag.
|
|
59
|
+
- The startup output in the terminal is easier to read: the version, a check mark per check, and each namespace's URLs lined up.
|
|
60
|
+
- Fixed: clicking the AI chat's $ or eye button twice quickly crashed with "Redundant state change".
|
|
61
|
+
|
|
62
|
+
## Changes in 0.13.0
|
|
63
|
+
|
|
64
|
+
- Dictation: text from speech-to-text tools such as Superwhisper, pasted into the search bar or any tag field, becomes your existing tags ("neural network" gives `neural-network`). Say "quote … end quote" for text, "minus" to exclude, "at" before meta tags such as `@todo`. In a note, the words after "start tags" go to its tag bar. The phrases are set in Dictation Settings, and one undo restores what was pasted.
|
|
65
|
+
- A quoted search with a space at its edge matches whole words: `" fat"` no longer finds "father".
|
|
66
|
+
- The AI keeps a record of what it did for each answer (notes read, searches, web pages opened), so questions like "did you search the web for that?" are answered from what actually happened.
|
|
67
|
+
- Dropping a `.txt`, `.md`, `.csv` or `.json` file stores it as before and adds its text as a child note, shown as Markdown, a table or formatted JSON. File pills show the extension (`.MD`, `.CSV`, …), and hovering a pill says that clicking downloads the file.
|
|
68
|
+
- Typing one letter in the tag bar now narrows the suggestions you were already shown instead of reordering them, so the tag you want is in the top five far more often.
|
|
69
|
+
|
|
52
70
|
## Changes in 0.12.0
|
|
53
71
|
|
|
54
72
|
- AI chat is now a tool-using agent: in one answer it can look up MetaList help, read and search the notes in your view, open web pages, and open menus, instead of picking a single route up front. Answers cite notes and web pages with clickable references, including each item listed from a web page.
|
|
@@ -12,6 +12,23 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
12
12
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
13
13
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
14
14
|
|
|
15
|
+
## Changes in 0.14.0
|
|
16
|
+
|
|
17
|
+
- A new login screen: one dark screen with the MetaList logo. The namespace, password and OK fade in together; once the password is accepted, the loading progress slides in with the current step and the seconds elapsed. When the first login after an update backs up and upgrades the namespace, a note under OK says so. The Session locked page has the same look, and there is no white flash between them.
|
|
18
|
+
- Web link titles: links to Reddit (including share links), YouTube, Vimeo, TikTok, Spotify and SoundCloud get their real titles. Lookups are paced per site, so a note full of links no longer trips a site's rate limit. Login, consent and site-name-only titles ("Sign in", "Reddit") show the link instead. The new command palette action Retry failed link titles asks every failed link again, with a progress dialog.
|
|
19
|
+
- Quoted search also matches link titles and the URLs hidden behind link labels, and the AI sees those URLs too. Pasting into a quoted search inserts the text as copied.
|
|
20
|
+
- `[[note id]]` is always a link, even in a note with a `[[ ]]` formatting tag.
|
|
21
|
+
- The startup output in the terminal is easier to read: the version, a check mark per check, and each namespace's URLs lined up.
|
|
22
|
+
- Fixed: clicking the AI chat's $ or eye button twice quickly crashed with "Redundant state change".
|
|
23
|
+
|
|
24
|
+
## Changes in 0.13.0
|
|
25
|
+
|
|
26
|
+
- Dictation: text from speech-to-text tools such as Superwhisper, pasted into the search bar or any tag field, becomes your existing tags ("neural network" gives `neural-network`). Say "quote … end quote" for text, "minus" to exclude, "at" before meta tags such as `@todo`. In a note, the words after "start tags" go to its tag bar. The phrases are set in Dictation Settings, and one undo restores what was pasted.
|
|
27
|
+
- A quoted search with a space at its edge matches whole words: `" fat"` no longer finds "father".
|
|
28
|
+
- The AI keeps a record of what it did for each answer (notes read, searches, web pages opened), so questions like "did you search the web for that?" are answered from what actually happened.
|
|
29
|
+
- Dropping a `.txt`, `.md`, `.csv` or `.json` file stores it as before and adds its text as a child note, shown as Markdown, a table or formatted JSON. File pills show the extension (`.MD`, `.CSV`, …), and hovering a pill says that clicking downloads the file.
|
|
30
|
+
- Typing one letter in the tag bar now narrows the suggestions you were already shown instead of reordering them, so the tag you want is in the top five far more often.
|
|
31
|
+
|
|
15
32
|
## Changes in 0.12.0
|
|
16
33
|
|
|
17
34
|
- AI chat is now a tool-using agent: in one answer it can look up MetaList help, read and search the notes in your view, open web pages, and open menus, instead of picking a single route up front. Answers cite notes and web pages with clickable references, including each item listed from a web page.
|
|
@@ -41,6 +41,7 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
41
41
|
NO_TOKEN_REFRESH_PATHS = [
|
|
42
42
|
f"{API_PREFIX}/auth/status", # Polling service pings this for connectivity
|
|
43
43
|
f"{API_PREFIX}/reminders/evaluate", # Reminder polling is not user-initiated activity
|
|
44
|
+
f"{API_PREFIX}/notes/link-titles/retry", # The retry dialog polls its progress
|
|
44
45
|
]
|
|
45
46
|
|
|
46
47
|
# Note: /api/notes/* paths are NOT in this list - they require auth when password is set
|
|
@@ -106,6 +106,18 @@ class SearchSuggestionInteractionRequest(TypedDict):
|
|
|
106
106
|
class TabSearchInteractionRequest(TypedDict):
|
|
107
107
|
searchQuery: Text
|
|
108
108
|
|
|
109
|
+
@with_config(ConfigDict(strict=True))
|
|
110
|
+
class DictationPasteRequest(TypedDict):
|
|
111
|
+
"""Text pasted into the search bar or the tag bar, and the field's current value."""
|
|
112
|
+
text: Text
|
|
113
|
+
target: Literal["search", "tags", "tag", "condition"]
|
|
114
|
+
current_value: Text
|
|
115
|
+
# The spoken phrases around a quoted phrase (Dictation Settings).
|
|
116
|
+
quote_open: Identifier
|
|
117
|
+
quote_close: Identifier
|
|
118
|
+
# Spoken before a search term to exclude it (Dictation Settings).
|
|
119
|
+
negate_phrase: Identifier
|
|
120
|
+
|
|
109
121
|
@with_config(ConfigDict(strict=True))
|
|
110
122
|
class TagSuggestionsRequest(TypedDict):
|
|
111
123
|
note_id: Identifier
|
|
@@ -136,6 +148,14 @@ class CreateChildRequest(TypedDict):
|
|
|
136
148
|
undoContext: UndoContext
|
|
137
149
|
viewport: Viewport
|
|
138
150
|
|
|
151
|
+
@with_config(ConfigDict(strict=True))
|
|
152
|
+
class CreateFilePreviewChildRequest(TypedDict):
|
|
153
|
+
fileId: Identifier
|
|
154
|
+
search_query: Text | None
|
|
155
|
+
clientId: Identifier
|
|
156
|
+
undoContext: UndoContext
|
|
157
|
+
viewport: Viewport
|
|
158
|
+
|
|
139
159
|
@with_config(ConfigDict(strict=True))
|
|
140
160
|
class UpdateNoteRequest(TypedDict):
|
|
141
161
|
clientId: Identifier
|
|
@@ -642,6 +642,7 @@ def stream_ai_chat(
|
|
|
642
642
|
model=payload.model,
|
|
643
643
|
)
|
|
644
644
|
provider_messages = ai_chat_store.provider_messages(session_key=session_key)
|
|
645
|
+
earlier_actions = ai_chat_store.earlier_actions(session_key=session_key)
|
|
645
646
|
initial_messages = agent_context_builder.build_initial_messages(
|
|
646
647
|
canonical_messages=provider_messages,
|
|
647
648
|
prompts=prompts,
|
|
@@ -654,7 +655,7 @@ def stream_ai_chat(
|
|
|
654
655
|
events = _stream_runtime_events(payload=payload, openai_api_key=openai_api_key,
|
|
655
656
|
session_key=session_key, provider_messages=provider_messages, prompts=prompts, skills=skills,
|
|
656
657
|
retrieval_settings=retrieval_settings, frozen_scope=frozen_scope, tagging_run=tagging_run,
|
|
657
|
-
web_settings=web_settings,
|
|
658
|
+
web_settings=web_settings, earlier_actions=earlier_actions,
|
|
658
659
|
initial_input_tokens=initial_approx_input_tokens)
|
|
659
660
|
|
|
660
661
|
return StreamingResponse(
|
|
@@ -673,6 +674,7 @@ async def _stream_runtime_events(
|
|
|
673
674
|
provider_messages: list[dict[str, str]], prompts: AgentPromptSet, skills: AgentSkillSet,
|
|
674
675
|
retrieval_settings: AgentRetrievalSettings, frozen_scope: ScopedSearchSnapshot,
|
|
675
676
|
tagging_run: TaggingRun, initial_input_tokens: int, web_settings: AgentWebSettings,
|
|
677
|
+
earlier_actions: list[dict[str, object]],
|
|
676
678
|
) -> AsyncIterator[dict[str, object]]:
|
|
677
679
|
action, start_label = 'provider_runtime', 'Connecting to OpenAI API'
|
|
678
680
|
ready_label = 'OpenAI API ready · 1,050,000-token context'
|
|
@@ -686,7 +688,7 @@ async def _stream_runtime_events(
|
|
|
686
688
|
selected_model=payload.model, thinking_level=payload.thinking_level,
|
|
687
689
|
canonical_messages=provider_messages, prompts=prompts, skills=skills,
|
|
688
690
|
retrieval_settings=retrieval_settings, web_settings=web_settings,
|
|
689
|
-
frozen_scope=frozen_scope, tagging_run=tagging_run)
|
|
691
|
+
frozen_scope=frozen_scope, tagging_run=tagging_run, earlier_actions=earlier_actions)
|
|
690
692
|
try:
|
|
691
693
|
async for event in events:
|
|
692
694
|
yield event
|
|
@@ -97,6 +97,7 @@ from app.services.client_state_service import save_client_preferences
|
|
|
97
97
|
from app.services.client_state_service import save_command_palette_usage
|
|
98
98
|
from app.services.openai_credentials import openai_credential_store
|
|
99
99
|
from app.services.input_errors import NamespaceInputRejected
|
|
100
|
+
from app.services.link_title_retry import stop_link_title_retry
|
|
100
101
|
|
|
101
102
|
|
|
102
103
|
router = APIRouter(prefix="/auth", tags=["auth2"])
|
|
@@ -595,6 +596,9 @@ def logout(
|
|
|
595
596
|
openai_credential_store.clear_session(session_key=session_key)
|
|
596
597
|
token_service.revoke_token(token)
|
|
597
598
|
shell_session_service.reset()
|
|
599
|
+
# Lock and login end a retry through the runtime generation; a passwordless
|
|
600
|
+
# logout does not change it, so stop the retry here.
|
|
601
|
+
stop_link_title_retry()
|
|
598
602
|
view_cache.clear()
|
|
599
603
|
reset_all_undo_state()
|
|
600
604
|
reset_sync_state()
|
|
@@ -712,6 +716,8 @@ def auth_status(
|
|
|
712
716
|
return {
|
|
713
717
|
"version": VERSION,
|
|
714
718
|
"database_user_version": database_user_version,
|
|
719
|
+
# The next login backs up and upgrades this database (the login screen says so).
|
|
720
|
+
"database_upgrade_pending": database_user_version < CURRENT_DATABASE_VERSION,
|
|
715
721
|
"authenticated": token is not None,
|
|
716
722
|
# Same answer as AuthService.has_password(), from the row already read.
|
|
717
723
|
"has_password": settings is not None and bool(settings.encryption_enabled),
|
|
@@ -20,9 +20,11 @@ from app.api.note_requests import (
|
|
|
20
20
|
SearchSuggestionInteractionRequest,
|
|
21
21
|
TabSearchInteractionRequest,
|
|
22
22
|
TagSuggestionsRequest,
|
|
23
|
+
DictationPasteRequest,
|
|
23
24
|
CreateNoteTopRequest,
|
|
24
25
|
CreateSiblingRequest,
|
|
25
26
|
CreateChildRequest,
|
|
27
|
+
CreateFilePreviewChildRequest,
|
|
26
28
|
UpdateNoteRequest,
|
|
27
29
|
SaveNoteRequest,
|
|
28
30
|
AddSelectedTextTagRequest,
|
|
@@ -61,9 +63,16 @@ from app.services.exception_capture import CapturedExceptionContext
|
|
|
61
63
|
from app.usecases.create_note import CmdCreateNote
|
|
62
64
|
from app.usecases.base import QueryCommand
|
|
63
65
|
from app.usecases.create_sibling import CmdCreateSibling
|
|
66
|
+
from app.services.file_registry import file_registry
|
|
64
67
|
from app.usecases.create_child import CmdCreateChild
|
|
68
|
+
from app.usecases.create_file_preview_child import CmdCreateFilePreviewChild
|
|
65
69
|
from app.usecases.update_content import CmdUpdateContent
|
|
66
70
|
from app.usecases.prefetch_link_titles import CmdPrefetchLinkTitles
|
|
71
|
+
from app.services.link_title_retry import (
|
|
72
|
+
link_title_retry_snapshot,
|
|
73
|
+
start_link_title_retry,
|
|
74
|
+
stop_link_title_retry,
|
|
75
|
+
)
|
|
67
76
|
from app.usecases.add_selected_text_tag import CmdAddSelectedTextTag
|
|
68
77
|
from app.usecases.tag_proposals import (
|
|
69
78
|
CmdAcceptTagProposal,
|
|
@@ -127,6 +136,7 @@ from app.services.html_export import build_notes_export_filename
|
|
|
127
136
|
from app.services.note_fullscreen import build_note_fullscreen_markup
|
|
128
137
|
from app.services.link_titles import link_title_store
|
|
129
138
|
from app.services.search_index import search_index
|
|
139
|
+
from app.services.dictation_cleanup import clean_dictated_paste
|
|
130
140
|
from app.services.tag_suggestions import suggest_tags_for_note
|
|
131
141
|
from app.services.undo_state import reset_undo_stack
|
|
132
142
|
from app.usecases.prioritize import list_prioritize_tag_suggestions
|
|
@@ -154,6 +164,26 @@ def prefetch_link_titles(request: Request, draft: LinkTitlePrefetchRequest) -> d
|
|
|
154
164
|
return CmdPrefetchLinkTitles(content=draft.content, tags=draft.tags).execute()
|
|
155
165
|
|
|
156
166
|
|
|
167
|
+
@router.get("/notes/link-titles/retry")
|
|
168
|
+
def link_title_retry_progress(request: Request) -> dict[str, object]:
|
|
169
|
+
require_request_auth_token(request)
|
|
170
|
+
return link_title_retry_snapshot()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@router.post("/notes/link-titles/retry")
|
|
174
|
+
@transactional_route
|
|
175
|
+
def start_link_title_retry_route(request: Request) -> dict[str, object]:
|
|
176
|
+
require_request_auth_token(request)
|
|
177
|
+
return start_link_title_retry()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@router.post("/notes/link-titles/retry/stop")
|
|
181
|
+
@transactional_route
|
|
182
|
+
def stop_link_title_retry_route(request: Request) -> dict[str, object]:
|
|
183
|
+
require_request_auth_token(request)
|
|
184
|
+
return stop_link_title_retry()
|
|
185
|
+
|
|
186
|
+
|
|
157
187
|
def _require_note_present(note_id: str, *, context: str) -> None:
|
|
158
188
|
if not isinstance(context, str) or not context:
|
|
159
189
|
raise ValueError("context must be a non-empty string")
|
|
@@ -551,6 +581,22 @@ def delete_tag_interactions(request: Request) -> Dict[str, object]:
|
|
|
551
581
|
return {"deletedCount": deleted_count}
|
|
552
582
|
|
|
553
583
|
|
|
584
|
+
@router.post("/notes/dictation-paste")
|
|
585
|
+
@transactional_route
|
|
586
|
+
def dictation_paste(payload: DictationPasteRequest) -> Dict[str, object]:
|
|
587
|
+
"""Read-only: the cleaned-up text to insert for a paste (docs/ui/dictation-paste.md)."""
|
|
588
|
+
text = clean_dictated_paste(
|
|
589
|
+
text=payload["text"],
|
|
590
|
+
target=payload["target"],
|
|
591
|
+
existing_tag_frequencies=search_index.list_explicit_tag_frequencies(),
|
|
592
|
+
current_value=payload["current_value"],
|
|
593
|
+
quote_open=payload["quote_open"],
|
|
594
|
+
quote_close=payload["quote_close"],
|
|
595
|
+
negate_phrase=payload["negate_phrase"],
|
|
596
|
+
)
|
|
597
|
+
return {"text": text}
|
|
598
|
+
|
|
599
|
+
|
|
554
600
|
@router.post("/notes/tag-suggestions")
|
|
555
601
|
@transactional_route
|
|
556
602
|
def tag_suggestions(payload: TagSuggestionsRequest) -> Dict[str, object]:
|
|
@@ -750,6 +796,27 @@ def create_child(request: Request, note_id: str, body: CreateChildRequest):
|
|
|
750
796
|
return cmd.execute()
|
|
751
797
|
|
|
752
798
|
|
|
799
|
+
@router.post("/notes/file-preview-child/{note_id}")
|
|
800
|
+
@transactional_route
|
|
801
|
+
def create_file_preview_child(request: Request, note_id: str, body: CreateFilePreviewChildRequest):
|
|
802
|
+
token = _require_bearer_token(request)
|
|
803
|
+
viewport = _require_viewport(body)
|
|
804
|
+
_require_note_present(note_id, context="notes.file-preview-child")
|
|
805
|
+
file_id = body["fileId"]
|
|
806
|
+
if not file_registry.has_file(file_id):
|
|
807
|
+
raise HTTPException(status_code=404, detail=f"File not found: {file_id}")
|
|
808
|
+
cmd = CmdCreateFilePreviewChild(
|
|
809
|
+
parent_note_id=note_id,
|
|
810
|
+
file_id=file_id,
|
|
811
|
+
search_query=body["search_query"],
|
|
812
|
+
token=token,
|
|
813
|
+
client_id=body["clientId"],
|
|
814
|
+
undo_context=body["undoContext"],
|
|
815
|
+
viewport=viewport,
|
|
816
|
+
)
|
|
817
|
+
return cmd.execute()
|
|
818
|
+
|
|
819
|
+
|
|
753
820
|
@router.put("/notes/{note_id}")
|
|
754
821
|
@transactional_route
|
|
755
822
|
def update_note(request: Request, note_id: str, body: UpdateNoteRequest):
|
|
@@ -45,7 +45,6 @@ def _env_int(name: str, default: int) -> int:
|
|
|
45
45
|
CRASH_SERVER_ON_FAIL = _env_flag("CRASH_SERVER_ON_FAIL", True)
|
|
46
46
|
DEV_ENFORCE_INTEGRITY_CHECKS = _env_flag("DEV_ENFORCE_INTEGRITY_CHECKS", False)
|
|
47
47
|
DISABLE_UNDO_SNAPSHOT = _env_flag("DISABLE_UNDO_SNAPSHOT", True)
|
|
48
|
-
STARTUP_ANIMATION_ENABLED = _env_flag("STARTUP_ANIMATION_ENABLED", False)
|
|
49
48
|
|
|
50
49
|
# Tag suggestions
|
|
51
50
|
TAG_SUGGESTION_CONNECTORS = "-_/."
|
|
@@ -94,6 +94,20 @@ class EncryptionAuditReport:
|
|
|
94
94
|
def startup_allowed(self) -> bool:
|
|
95
95
|
return self.namespace_count > 0 and len(self.fatal_findings) == 0
|
|
96
96
|
|
|
97
|
+
def namespace_statuses(self) -> list[tuple[str, str]]:
|
|
98
|
+
"""(namespace, PASS | MIGRATION REQUIRED | FAIL | SKIPPED (not encrypted)) per namespace."""
|
|
99
|
+
statuses: list[tuple[str, str]] = []
|
|
100
|
+
for result in self.results:
|
|
101
|
+
result_status = "SKIPPED (not encrypted)"
|
|
102
|
+
if result.is_encrypted:
|
|
103
|
+
result_status = "PASS"
|
|
104
|
+
if result.findings:
|
|
105
|
+
result_status = "MIGRATION REQUIRED"
|
|
106
|
+
if any(not finding.is_migration_deferred for finding in result.findings):
|
|
107
|
+
result_status = "FAIL"
|
|
108
|
+
statuses.append((result.namespace, result_status))
|
|
109
|
+
return statuses
|
|
110
|
+
|
|
97
111
|
def render_text(self) -> str:
|
|
98
112
|
status = "FAIL"
|
|
99
113
|
if self.passed:
|
|
@@ -110,15 +124,8 @@ class EncryptionAuditReport:
|
|
|
110
124
|
),
|
|
111
125
|
f"Sensitive payloads checked: {self.checked_payload_count}",
|
|
112
126
|
]
|
|
113
|
-
for
|
|
114
|
-
|
|
115
|
-
if result.is_encrypted:
|
|
116
|
-
result_status = "PASS"
|
|
117
|
-
if result.findings:
|
|
118
|
-
result_status = "MIGRATION REQUIRED"
|
|
119
|
-
if any(not finding.is_migration_deferred for finding in result.findings):
|
|
120
|
-
result_status = "FAIL"
|
|
121
|
-
lines.append(f"- {result.namespace}: {result_status}")
|
|
127
|
+
for namespace, result_status in self.namespace_statuses():
|
|
128
|
+
lines.append(f"- {namespace}: {result_status}")
|
|
122
129
|
if self.findings:
|
|
123
130
|
lines.append("Findings:")
|
|
124
131
|
for finding in self.findings:
|
|
@@ -26,6 +26,8 @@ CAPTURE_BOUNDARIES = {
|
|
|
26
26
|
'app/api/routes/app_updates.py:update_status:lookup': ('AppUpdateRejected', 'FileNotFoundError'),
|
|
27
27
|
# Release smoke polls only its own disposable HTTP listeners during an actual update.
|
|
28
28
|
'scripts/smoke_self_update.py:_has_updated_namespace:probe_capture': ('HTTPError',),
|
|
29
|
+
# Release smoke cleanup: on Windows an exiting process refuses termination; the wait then checks it stopped.
|
|
30
|
+
'scripts/smoke_installed_package.py:_terminate_on_windows:exit_capture': ('ProcessLookupError', 'PermissionError'),
|
|
29
31
|
# A child can exit between poll and terminate; hung children must be killed and reaped.
|
|
30
32
|
'app/services/namespace_switcher.py:_stop_failed_namespace_launch:terminate_capture': ('ProcessLookupError',),
|
|
31
33
|
'app/services/namespace_switcher.py:_stop_failed_namespace_launch:wait_capture': ('TimeoutExpired',),
|
|
@@ -125,6 +127,12 @@ CAPTURE_BOUNDARIES = {
|
|
|
125
127
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
126
128
|
'app/services/link_titles.py:fetch_link_title:target_capture': ('PublicHttpTargetRejected',),
|
|
127
129
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
130
|
+
'app/services/link_titles.py:_fetch_oembed_title:target_capture': ('PublicHttpTargetRejected',),
|
|
131
|
+
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
132
|
+
'app/services/link_titles.py:_fetch_oembed_title:json_capture': ('JSONDecodeError', 'UnicodeDecodeError'),
|
|
133
|
+
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
134
|
+
'app/services/link_titles.py:_download_oembed:capture': ('TimeoutException', 'NetworkError', 'HTTPError', 'TimeoutException', 'NetworkError', 'ProtocolError'),
|
|
135
|
+
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
128
136
|
'app/services/namespace_deletion_worker.py:_is_process_running:kill_capture': ('ProcessLookupError', 'PermissionError'),
|
|
129
137
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
130
138
|
'app/services/namespace_deletion_worker.py:_send_signal_if_running:signal_capture': ('ProcessLookupError',),
|
|
@@ -16,7 +16,7 @@ from app.api.upload_limits import UploadLimitMiddleware
|
|
|
16
16
|
from app.presentation.templates import get_templates
|
|
17
17
|
from .api import dev
|
|
18
18
|
from .api.middleware.auth import AuthMiddleware
|
|
19
|
-
from app.config import ACTIVE_NAMESPACE,
|
|
19
|
+
from app.config import ACTIVE_NAMESPACE, VERSION
|
|
20
20
|
from .db.session import begin_writer, enable_read_guard
|
|
21
21
|
from .db.schema import initialize_schema
|
|
22
22
|
from .db.migrations import CURRENT_DATABASE_VERSION
|
|
@@ -61,6 +61,7 @@ from app.services.diagnostics import track_request
|
|
|
61
61
|
from app.services.diagnostics import write_encrypted_exception_trace
|
|
62
62
|
from app.security.sensitive_logging import traceback_frame_summary
|
|
63
63
|
from app.api.request_auth import clear_auth_cookie
|
|
64
|
+
from app.presentation.login_page import login_is_certainly_needed
|
|
64
65
|
from app.api.routes.notes import router as api2_router
|
|
65
66
|
from app.api.routes.auth import router as api2_auth_router
|
|
66
67
|
from app.api.routes.app_updates import router as api2_app_updates_router
|
|
@@ -463,7 +464,7 @@ async def home(request: Request, db: Annotated[SafeSession, Depends(get_db)]):
|
|
|
463
464
|
asset_version=ASSET_VERSION,
|
|
464
465
|
page_title=_resolve_page_title(base_title="MetaList"),
|
|
465
466
|
needs_auth=True,
|
|
466
|
-
|
|
467
|
+
shows_login_at_once=login_is_certainly_needed(request),
|
|
467
468
|
)
|
|
468
469
|
return template.render(
|
|
469
470
|
request=request,
|
|
@@ -472,10 +473,11 @@ async def home(request: Request, db: Annotated[SafeSession, Depends(get_db)]):
|
|
|
472
473
|
asset_version=ASSET_VERSION,
|
|
473
474
|
page_title=_resolve_page_title(base_title="MetaList"),
|
|
474
475
|
needs_auth=False,
|
|
475
|
-
|
|
476
|
+
shows_login_at_once=False,
|
|
476
477
|
)
|
|
477
478
|
|
|
478
479
|
|
|
480
|
+
|
|
479
481
|
@app.get("/maintenance", response_class=HTMLResponse)
|
|
480
482
|
async def maintenance_page(request: Request):
|
|
481
483
|
"""Maintenance mode page shown during bulk operations."""
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Whether the page opens straight on the login screen (docs/AI-SUMMARY.md, Login screen)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from starlette.requests import Request
|
|
6
|
+
|
|
7
|
+
from app.api.request_auth import AUTH_COOKIE_NAME
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def login_is_certainly_needed(request: Request) -> bool:
|
|
11
|
+
"""Whether a password namespace's page can open on the login screen at once,
|
|
12
|
+
with no white page before the browser checks its session: a re-login was asked
|
|
13
|
+
for (the Session locked page's Go to Login), or the browser has no session."""
|
|
14
|
+
if not isinstance(request, Request):
|
|
15
|
+
raise TypeError("request must be a Request")
|
|
16
|
+
if request.query_params.get("force_reauth") == "1":
|
|
17
|
+
return True
|
|
18
|
+
return request.cookies.get(AUTH_COOKIE_NAME) is None
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""The agent's own record of what it did for an answer.
|
|
2
|
+
|
|
3
|
+
Each tool call becomes one short entry: what was asked and what came of it,
|
|
4
|
+
never the content a tool returned (page text and notes can be huge, and the
|
|
5
|
+
model can read them again). The entries are kept with the answer for the rest of
|
|
6
|
+
the chat and given to the model on later turns, so a question such as "did you
|
|
7
|
+
search the web for that?" is answered from what actually happened. Only the
|
|
8
|
+
model sees them.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
_NOTE_READ_TOOLS = frozenset({"read_view_notes", "search_view_notes"})
|
|
17
|
+
_OPERATION_TOOLS = frozenset({"summarize_view", "propose_tag_generation", "propose_tag_review"})
|
|
18
|
+
_KNOWN_TOOLS = _NOTE_READ_TOOLS | _OPERATION_TOOLS | {
|
|
19
|
+
"lookup_metalist_help", "view_overview", "open_web_pages", "open_menu",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def describe_action(*, name: str, arguments: str, result_content: str, is_error: bool) -> dict[str, object]:
|
|
24
|
+
"""One log entry for a tool call, from its JSON arguments and JSON result."""
|
|
25
|
+
# A rejected call may name a tool that does not exist: it is still recorded.
|
|
26
|
+
if is_error:
|
|
27
|
+
return {"tool": name, "rejected": True}
|
|
28
|
+
if name not in _KNOWN_TOOLS:
|
|
29
|
+
raise ValueError(f"No action log entry for unknown tool: {name!r}")
|
|
30
|
+
parsed_arguments = json.loads(arguments)
|
|
31
|
+
assert isinstance(parsed_arguments, dict), "Tool arguments are a JSON object"
|
|
32
|
+
if name in _OPERATION_TOOLS:
|
|
33
|
+
return {"tool": name, "arguments": parsed_arguments}
|
|
34
|
+
result = json.loads(result_content)
|
|
35
|
+
assert isinstance(result, dict), "Tool results are a JSON object"
|
|
36
|
+
if name == "lookup_metalist_help":
|
|
37
|
+
return {"tool": name, "topics": list(parsed_arguments["topics"])}
|
|
38
|
+
if name == "view_overview":
|
|
39
|
+
return {"tool": name, "notes_in_view": result["note_count"], "trees_in_view": result["tree_count"]}
|
|
40
|
+
if name == "open_menu":
|
|
41
|
+
return {"tool": name, "menu": result["label"], "status": result["status"]}
|
|
42
|
+
if name == "open_web_pages":
|
|
43
|
+
return {"tool": name, "pages": [_page_entry(page) for page in result["pages"]]}
|
|
44
|
+
entry: dict[str, object] = {"tool": name}
|
|
45
|
+
if name == "search_view_notes":
|
|
46
|
+
entry["query"] = parsed_arguments["query"]
|
|
47
|
+
entry["matching_notes"] = result["matching_note_count"]
|
|
48
|
+
entry["trees_read"] = len(result["trees"])
|
|
49
|
+
entry["trees_left_unread"] = len(result["unread_root_ids"])
|
|
50
|
+
entry["trees_too_large"] = len(result["too_large_root_ids"])
|
|
51
|
+
return entry
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _page_entry(page: dict[str, object]) -> dict[str, object]:
|
|
55
|
+
"""The address as asked, whether it opened, and its title when it did."""
|
|
56
|
+
title = ""
|
|
57
|
+
if page["status"] == "ok":
|
|
58
|
+
title = page["title"]
|
|
59
|
+
return {"url": page["requested_url"], "status": page["status"], "title": title}
|
|
@@ -52,6 +52,7 @@ from app.services.bulk_operation import bulk_operation_guard
|
|
|
52
52
|
from app.services.agent.citation_tokens import ShortCitationTranslator
|
|
53
53
|
from app.services.agent.note_aliases import NoteAliases
|
|
54
54
|
from app.services.agent.execution_errors import AgentExecutionError
|
|
55
|
+
from app.services.agent.action_log import describe_action
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
MAX_AGENT_TURNS = 8
|
|
@@ -82,6 +83,8 @@ class AgentLoopState:
|
|
|
82
83
|
self.web_evidence: list[WebPageEvidence] = []
|
|
83
84
|
self.capabilities = capabilities
|
|
84
85
|
self.content = ""
|
|
86
|
+
# What this answer did, for later turns (action_log.py).
|
|
87
|
+
self.actions: list[dict[str, object]] = []
|
|
85
88
|
# Note text shown to the model, and full-mode addresses the user approved.
|
|
86
89
|
self.note_text_parts: list[str] = [selected_note_text]
|
|
87
90
|
self.approved_urls: set[str] = set()
|
|
@@ -129,14 +132,19 @@ class AgentLoopState:
|
|
|
129
132
|
"reference_note_ids": list(self.reference_note_ids),
|
|
130
133
|
"reference_web_ids": self.reference_web_ids()}
|
|
131
134
|
|
|
135
|
+
def record_action(self, *, call: dict[str, str], result_content: str, is_error: bool) -> None:
|
|
136
|
+
self.actions.append(describe_action(name=call["name"], arguments=call["arguments"],
|
|
137
|
+
result_content=result_content, is_error=is_error))
|
|
138
|
+
|
|
132
139
|
def done_event(self) -> dict[str, object]:
|
|
133
140
|
return {"type": "done", "reference_note_ids": list(self.reference_note_ids),
|
|
134
|
-
"reference_web_ids": self.reference_web_ids()}
|
|
141
|
+
"reference_web_ids": self.reference_web_ids(), "actions": list(self.actions)}
|
|
135
142
|
|
|
136
143
|
|
|
137
144
|
class AgentLoopMixin:
|
|
138
145
|
async def _run_agent_loop(
|
|
139
146
|
self, *, run, canonical_messages: list[dict[str, str]], frozen_scope: ScopedSearchSnapshot, tagging_run,
|
|
147
|
+
earlier_actions: list[dict[str, object]],
|
|
140
148
|
) -> AsyncIterator[dict[str, object]]:
|
|
141
149
|
if not isinstance(frozen_scope, ScopedSearchSnapshot):
|
|
142
150
|
raise TypeError("frozen_scope must be ScopedSearchSnapshot")
|
|
@@ -167,6 +175,7 @@ class AgentLoopMixin:
|
|
|
167
175
|
messages = self._context_builder.build_agent_messages(
|
|
168
176
|
canonical_messages=canonical_messages, skills=run.skills, web_settings=run.web_settings,
|
|
169
177
|
snapshot=snapshot, available_urls=capabilities.normalized_urls, note_aliases=note_aliases,
|
|
178
|
+
earlier_actions=earlier_actions,
|
|
170
179
|
)
|
|
171
180
|
self._trace_store.append_event(
|
|
172
181
|
session_key=run.session_key, run_id=run.run_id, event_type="FROZEN_SCOPE",
|
|
@@ -238,16 +247,21 @@ class AgentLoopMixin:
|
|
|
238
247
|
result = tool_message_result({"summary": "not started",
|
|
239
248
|
"reason": "The current view has no notes to summarize."})
|
|
240
249
|
self._record_tool_call(run=run, call=operation, result_text=result.content)
|
|
250
|
+
state.record_action(call=operation, result_content=result.content, is_error=False)
|
|
241
251
|
messages.append({"role": "tool", "tool_call_id": operation["id"], "name": operation["name"],
|
|
242
252
|
"content": result.content})
|
|
243
253
|
answered_without_operation = True
|
|
244
254
|
elif not isinstance(parsed, ToolResult):
|
|
245
255
|
self._record_tool_call(run=run, call=operation, result_text="(operation started)")
|
|
256
|
+
state.record_action(call=operation, result_content="{}", is_error=False)
|
|
246
257
|
async with aclosing(self._stream_agent_operation(
|
|
247
258
|
run=run, canonical_messages=canonical_messages, snapshot=snapshot,
|
|
248
259
|
tagging_run=tagging_run, arguments=parsed, state=state,
|
|
249
260
|
)) as operation_events:
|
|
250
261
|
async for event in operation_events:
|
|
262
|
+
# The operation ends the answer: its completion carries the log.
|
|
263
|
+
if event["type"] == "done":
|
|
264
|
+
event = {**event, "actions": list(state.actions)}
|
|
251
265
|
yield event
|
|
252
266
|
return
|
|
253
267
|
if answered_without_operation:
|
|
@@ -266,6 +280,7 @@ class AgentLoopMixin:
|
|
|
266
280
|
result = result_holder[0]
|
|
267
281
|
results.append(result)
|
|
268
282
|
state.add_tool_result(result)
|
|
283
|
+
state.record_action(call=call, result_content=result.content, is_error=result.is_error)
|
|
269
284
|
self._record_tool_call(run=run, call=call, result_text=result.content)
|
|
270
285
|
messages.append({"role": "tool", "tool_call_id": call["id"], "name": call["name"],
|
|
271
286
|
"content": result.content})
|
|
@@ -78,7 +78,8 @@ class AgentContextBuilder:
|
|
|
78
78
|
"none": (
|
|
79
79
|
"Web access is disabled. You cannot search or open pages. If the "
|
|
80
80
|
"request requires the web, state that limitation and tell the user "
|
|
81
|
-
"they can enable contextual or full web access in AI Agent Settings."
|
|
81
|
+
"they can enable contextual or full web access in AI Agent Settings. Label "
|
|
82
|
+
"anything you suggest from your own knowledge as not looked up."
|
|
82
83
|
),
|
|
83
84
|
"contextual": (
|
|
84
85
|
"You may open only exact URLs in available_urls, plus addresses written in "
|
|
@@ -86,7 +87,11 @@ class AgentContextBuilder:
|
|
|
86
87
|
"A #fragment is ignored "
|
|
87
88
|
"when comparing, so https://a.example/page#part is the same address as "
|
|
88
89
|
"https://a.example/page. You cannot search, and links discovered inside "
|
|
89
|
-
"opened pages do not become available."
|
|
90
|
+
"opened pages do not become available. When a request needs a search (for "
|
|
91
|
+
"example newer or recent papers, releases or news), say plainly that this mode "
|
|
92
|
+
"only opens links already in the notes or chat, that 'Open any public web page' "
|
|
93
|
+
"in AI Agent Settings allows searching, and label anything you suggest from your "
|
|
94
|
+
"own knowledge as not looked up."
|
|
90
95
|
),
|
|
91
96
|
"full": (
|
|
92
97
|
"You may open any direct public HTTP(S) page, including Google "
|
|
@@ -158,6 +163,7 @@ class AgentContextBuilder:
|
|
|
158
163
|
snapshot: ScopedSearchSnapshot,
|
|
159
164
|
available_urls: tuple[str, ...],
|
|
160
165
|
note_aliases: NoteAliases,
|
|
166
|
+
earlier_actions: list[dict[str, object]],
|
|
161
167
|
) -> list[dict[str, object]]:
|
|
162
168
|
"""The tool-using agent's opening conversation.
|
|
163
169
|
|
|
@@ -189,6 +195,16 @@ class AgentContextBuilder:
|
|
|
189
195
|
{"role": "user", "content": "SELECTED_NOTE_CONTEXT\n" + json.dumps(view_context, sort_keys=True, separators=(",", ":"))},
|
|
190
196
|
*self.append_web_access_context(messages=[], settings=web_settings, available_urls=available_urls),
|
|
191
197
|
]
|
|
198
|
+
if earlier_actions:
|
|
199
|
+
context_messages.append({"role": "user", "content": "EARLIER_ACTIONS\n" + json.dumps({
|
|
200
|
+
"instruction": (
|
|
201
|
+
"Your own record of what you did for each earlier answer in this chat, oldest first: "
|
|
202
|
+
"the tools you called, what you asked for, and what came of them (page text and note "
|
|
203
|
+
"content are not repeated here). Answer questions about how an earlier answer was made "
|
|
204
|
+
"only from this record. If it does not show something, say you cannot tell."
|
|
205
|
+
),
|
|
206
|
+
"answers": earlier_actions,
|
|
207
|
+
}, sort_keys=True, separators=(",", ":"))})
|
|
192
208
|
return [
|
|
193
209
|
*system_messages,
|
|
194
210
|
*[dict(message) for message in canonical_messages[:-1]],
|
|
@@ -16,6 +16,7 @@ HELP_TOPICS = {
|
|
|
16
16
|
'ai': ('AI and tag proposals', 'OpenAI settings, context limits, prompts/skills, history export, and AI tag proposals: generation, acceptance, rejection/removal and bulk undo limits. This topic alone covers proposal workflow explanations.'),
|
|
17
17
|
'privacy': ('Privacy and security', 'Cloud disclosure, gray notes when hovering chat, password exclusion, encryption and credentials.'),
|
|
18
18
|
'data': ('Namespaces and backups', 'Namespaces, backup/restore, HTML export, ports and updates.'),
|
|
19
|
+
'dictation': ('Dictation (speech to text)', 'Pasting dictated text from speech-to-text tools such as Superwhisper into the search bar, tag bar or a note: how words become tags, spoken dash/quote/or/not, "at to do" meta tags, the "start tags" phrase in notes, undo, and Dictation Settings.'),
|
|
19
20
|
'releases': ('Release notes', 'What changed in each MetaList version (what is new, when a feature or fix arrived).'),
|
|
20
21
|
}
|
|
21
22
|
HelpTopic = Literal[tuple(HELP_TOPICS)]
|
|
@@ -103,6 +103,13 @@ last tool call. Answer the user's exact current question. Use the conversation t
|
|
|
103
103
|
resolve follow-ups such as "try again"; earlier answers are not evidence about the
|
|
104
104
|
current view, and earlier citations must not be reused.
|
|
105
105
|
|
|
106
|
+
`EARLIER_ACTIONS` is your own record of what you did for each earlier answer in
|
|
107
|
+
this chat: the tools you called and what came of them. When asked how an earlier
|
|
108
|
+
answer was made (did you search the web, which pages, did you read the notes),
|
|
109
|
+
answer from that record, including the searches and pages it lists. If the record
|
|
110
|
+
does not show something, say you cannot tell; never deny or claim an action
|
|
111
|
+
otherwise.
|
|
112
|
+
|
|
106
113
|
Notes are identified by short ids such as `n12`. Cite every claim drawn from a note
|
|
107
114
|
with its id in double brackets, copying the `note_id` of the note whose
|
|
108
115
|
`content_text` supports it (a child, not merely its root), directly after the
|