MetaList 0.7.0__tar.gz → 0.7.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metalist-0.7.0 → metalist-0.7.2}/MANIFEST.in +2 -0
- {metalist-0.7.0/metalist.egg-info → metalist-0.7.2}/PKG-INFO +21 -1
- {metalist-0.7.0 → metalist-0.7.2}/README.md +20 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/ai.py +53 -104
- {metalist-0.7.0 → metalist-0.7.2}/app/exception_boundaries.py +2 -12
- metalist-0.7.2/app/network_settings.py +61 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/request_boundary.py +1 -74
- metalist-0.7.2/app/security/request_hosts.py +83 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/actions.py +14 -77
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/cloud_privacy.py +33 -9
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/context.py +67 -22
- metalist-0.7.2/app/services/agent/help_catalog.py +43 -0
- metalist-0.7.2/app/services/agent/history.py +106 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/investigation.py +5 -3
- metalist-0.7.2/app/services/agent/judging.py +15 -0
- metalist-0.7.2/app/services/agent/menu_actions.py +63 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/openai_inference.py +16 -6
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/prompts/final-response.md +14 -0
- metalist-0.7.2/app/services/agent/prompts/help-response.md +25 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/prompts/system.md +24 -7
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/retrieval_settings.py +7 -31
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/runtime.py +128 -137
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/scope.py +109 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/skill_settings.py +8 -1
- metalist-0.7.2/app/services/agent/skills/help-ai.md +79 -0
- metalist-0.7.2/app/services/agent/skills/help-data.md +40 -0
- metalist-0.7.2/app/services/agent/skills/help-formatting.md +176 -0
- metalist-0.7.2/app/services/agent/skills/help-menus.md +116 -0
- metalist-0.7.2/app/services/agent/skills/help-notes.md +200 -0
- metalist-0.7.2/app/services/agent/skills/help-privacy.md +135 -0
- metalist-0.7.2/app/services/agent/skills/help-references.md +106 -0
- metalist-0.7.2/app/services/agent/skills/help-reminders.md +152 -0
- metalist-0.7.2/app/services/agent/skills/help-search.md +214 -0
- metalist-0.7.2/app/services/agent/skills/help-tags.md +354 -0
- metalist-0.7.0/app/services/agent/ollama_inference.py → metalist-0.7.2/app/services/agent/structured_inference.py +22 -151
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/trace.py +82 -7
- {metalist-0.7.0 → metalist-0.7.2}/app/services/ai_chat_stream.py +2 -3
- {metalist-0.7.0 → metalist-0.7.2}/app/services/client_state_service.py +10 -17
- {metalist-0.7.0 → metalist-0.7.2}/app/services/content_formatting.py +51 -2
- {metalist-0.7.0 → metalist-0.7.2}/app/services/search_index.py +52 -11
- {metalist-0.7.0 → metalist-0.7.2}/app/services/snapshot.py +3 -1
- {metalist-0.7.0 → metalist-0.7.2}/app/startup_sanity_config.py +0 -5
- metalist-0.7.2/app/static/config/agent-menu-actions.json +326 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/config/command_palette_tags.json +3 -3
- {metalist-0.7.0 → metalist-0.7.2}/app/static/css/main.css +29 -22
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/main.js +1 -0
- metalist-0.7.2/app/static/js/modules/ai-chat/agent-menu-actions.js +43 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +2 -22
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +16 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/ai-chat-api.js +30 -101
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +37 -9
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +8 -12
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +4 -15
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/auth.js +8 -20
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/command-palette-controller.js +51 -54
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/config.js +2 -1
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/ai-agent-settings-modal.js +48 -236
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/backup-restore-modal.js +2 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/base-modal.js +8 -3
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/delete-namespace-modal.js +3 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/namespace-modals.js +12 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/password-modal.js +6 -3
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/session-timeout-modal.js +3 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/version-info-modal.js +5 -1
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/actions/content-actions.js +33 -10
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/events/context-menu-events.js +6 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/events/keyboard-events.js +1 -1
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/events/mouse-events.js +20 -0
- metalist-0.7.2/app/static/js/modules/session-auth.js +43 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/templates/index.html +3 -2
- {metalist-0.7.0 → metalist-0.7.2}/app/version.py +1 -1
- {metalist-0.7.0 → metalist-0.7.2}/main.py +9 -0
- {metalist-0.7.0 → metalist-0.7.2/metalist.egg-info}/PKG-INFO +21 -1
- {metalist-0.7.0 → metalist-0.7.2}/metalist.egg-info/SOURCES.txt +20 -3
- metalist-0.7.0/app/services/managed_ollama_runtime.py +0 -499
- metalist-0.7.0/app/services/ollama_provider.py +0 -519
- metalist-0.7.0/app/static/js/modules/session-auth.js +0 -22
- {metalist-0.7.0 → metalist-0.7.2}/app/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/deps.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/dev.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/middleware/auth.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/note_requests.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/request_auth.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/app_updates.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/auth.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/backups.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/files.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/notes.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/ontology.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/reminders.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/remote_images.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/routes/test.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/transactions.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/api/upload_limits.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/config.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/data_directory.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/engine.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/file_schema.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/file_session.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/files_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/link_titles_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/live_recovery.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/migrations.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/notes_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/reminders_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/retire_sounds.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/schema.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/search_history_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/session.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/settings_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/tab_state_sql.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/db/version.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/encryption_audit.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/https_proxy.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/main.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/commands.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/database.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/entities.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/enums.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/linked_list.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/list_operations.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/list_traversal.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/note_crud.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/models/utils.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/presentation/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/presentation/render/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/presentation/templates.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/authenticated_logging.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/encryption.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/http_headers.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/note_html.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/sensitive_cache.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/sensitive_logging.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/shell_execution.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/security/validation_errors.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/server_runtime.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/evidence_serialization.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/inference.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/model_policy.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/openai_cost_tracking.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/permissions.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/prompt_settings.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/prompts/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/prompts/tool-result.md +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/skills/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/skills/scoped-investigation.md +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/tagging.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/tagging_run.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/token_estimation.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/agent/tools.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/ai_chat.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/ai_chat_rendering.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/app_update_worker.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/app_updates.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/auth.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/auth_cache_state.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/auth_service.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/backlink_index.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/backlinks.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/backup_service.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/backup_settings_service.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/bulk_operation.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/content_cache.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/diagnostics.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/embedded_references.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/encryption.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/exception_capture.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/file_registry.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/file_storage.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/footnote_layout.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/footnote_rendering.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/hierarchy.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/html_export.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/html_unformatting.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/hydration_state.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/image_size_formatting.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/inline_image_occurrences.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/input_errors.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/integrity.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/latex_rendering.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/link_titles.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/login_rate_limit.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/maintenance_mode.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/markdown_rendering.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/namespace_deletion_worker.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/namespace_rename_worker.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/namespace_runtime_guard.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/namespace_switcher.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/note_fullscreen.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/note_image_tags.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/note_ordering.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/note_store.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/ontology_rules_store.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/openai_credentials.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/password_note_fields.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/reference_presentation.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/reminders.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/remote_image_proxy.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/request_recovery.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/resource_limits.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/root_sorting.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/runtime_generation.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/runtime_hardening.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/runtime_lock.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/search_history.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/search_history_storage.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/search_query.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/search_text.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/selected_text_tag.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/self_update.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/session_timeout_service.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/shell_session_service.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/store.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/structured_note_renderers.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/sync.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/sync_state.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/tab_state.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/tag_case.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/tag_ontology.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/tag_rename.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/tag_suggestions.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/tag_term_matching.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/test_reset.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/tokens.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/undo_state.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/update_backups.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/update_preflight.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/view_cache.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/view_diff.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/view_state.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/services/windows_process_control.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/startup_environment.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/startup_js_sanity.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/startup_sanity.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/css/floating-notes.css +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/css/forms.css +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/img/favicon.ico +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/locked.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/agent-prompt-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/api-client.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/api-failure-classification-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/app-update-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/application-state.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/endpoint-registry.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/preferences-store.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/connectivity-monitor.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/dom-utils-fixed.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/elapsed-time.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/expected-errors.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/login-namespace-picker.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/maintenance.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/agent-prompt-editor-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/backup-result-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/confirmation-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/help-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/ontology-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/mode-context.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/note-html-sanitizer.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/password-operation-response.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/password-policy.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/password-strength.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/selection-markers.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/namespace-deleted.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/namespace-renamed.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/dompurify-3.4.13.LICENSE.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/dompurify-3.4.13.min.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/markdown-it-14.3.2.LICENSE.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/markdown-it-14.3.2.min.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/note-html-policy.json +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/static/video/login-startup.mp4 +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/templates/base.html +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/templates/locked.html +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/templates/maintenance.html +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/templates/namespace_deleted.html +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/templates/namespace_renamed.html +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/templates/notes_list.html +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/upload_limits.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/add_selected_text_tag.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/base.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/bulk_tag_proposals.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/collapse.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/copy_note.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/create_child.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/create_note.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/create_sibling.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/delete_tag.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/expand.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/indent.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/lock.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/move.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/move_to_top.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/outdent.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/paste_child.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/prefetch_link_titles.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/prioritize.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/redo.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/rename_tag.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/resize_image.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/run_shell.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/search_context_tags.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/split_note.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/tag_proposals.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/toggle_reference_mode.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/undo.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/unformat_content.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/update_content.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/usecases/view.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/utils/__init__.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/utils/encryption.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/app/utils/text_utils.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/convert-from-legacy.py +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/metalist.egg-info/requires.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/pyproject.toml +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.7.0 → metalist-0.7.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metalist
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
|
|
5
5
|
Project-URL: Homepage, https://github.com/evolvingstuff/metalist
|
|
6
6
|
Project-URL: Repository, https://github.com/evolvingstuff/metalist
|
|
@@ -48,6 +48,14 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
48
48
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
49
49
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
50
50
|
|
|
51
|
+
## Changes in 0.7.2
|
|
52
|
+
|
|
53
|
+
- Login, hydration, and workspace requests share one initialized browser-tab identity. Losing the `sessionStorage` copy while opening the workspace no longer causes the reported missing-tab-ID crash. The external trigger for that storage loss remains unconfirmed.
|
|
54
|
+
- AI chat preserves the edited note and includes its permitted tree, tags, and cached URL titles. Search redaction and cloud privacy restrictions apply to every node; blocked selections expose only their availability reason.
|
|
55
|
+
- Added on-demand AI help and menu actions, privacy previews, and Copy Response throughout assistant message bubbles. OpenAI is the supported inference provider.
|
|
56
|
+
- LLM regressions use current production prompts, default to five trials with cache-aware parallel scheduling, and can run only cases affected by prompt or skill changes.
|
|
57
|
+
- Improved Grammarly edit preservation and search suggestions that match the complete active clause.
|
|
58
|
+
|
|
51
59
|
## Changes in 0.6.3
|
|
52
60
|
|
|
53
61
|
- Restored HTTPS connection reuse and aligned the pending accept queue with the existing worker capacity, so a browser’s six-connection startup burst is admitted.
|
|
@@ -213,6 +221,18 @@ METALIST_HOST=192.168.1.20 metalist
|
|
|
213
221
|
```
|
|
214
222
|
On a fresh machine, that first launch also creates the default TLS cert pair automatically. Then open either `http://192.168.1.20:8000` or `https://192.168.1.20:8443` from the other machine.
|
|
215
223
|
|
|
224
|
+
Starting with 0.7.1, an explicit `METALIST_HOST` or `METALIST_ALLOWED_HOSTS`
|
|
225
|
+
configuration is saved in `~/MetaList/network-settings.json` (under
|
|
226
|
+
`METALIST_DATA_DIRECTORY` when overridden). Subsequent source launches, plain
|
|
227
|
+
`metalist` launches, and updates reuse it. Environment values override and update
|
|
228
|
+
the corresponding saved settings. This file stores only the bind address and
|
|
229
|
+
allowed hosts; namespace ports remain in their launch profiles, and shell access
|
|
230
|
+
still requires `--enable-shell` on each launch. Invalid settings stop startup
|
|
231
|
+
with an error. Fresh installations continue to bind to localhost by default.
|
|
232
|
+
To switch back to local-only access, run `METALIST_HOST=127.0.0.1 metalist` once.
|
|
233
|
+
Older installed versions do not read this file; keep supplying their LAN settings
|
|
234
|
+
until upgrading to 0.7.1 or later.
|
|
235
|
+
|
|
216
236
|
To keep `@shell` available on the host laptop while allowing another laptop to
|
|
217
237
|
use normal MetaList features, bind both interfaces and explicitly allow the LAN
|
|
218
238
|
address:
|
|
@@ -12,6 +12,14 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
12
12
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
13
13
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
14
14
|
|
|
15
|
+
## Changes in 0.7.2
|
|
16
|
+
|
|
17
|
+
- Login, hydration, and workspace requests share one initialized browser-tab identity. Losing the `sessionStorage` copy while opening the workspace no longer causes the reported missing-tab-ID crash. The external trigger for that storage loss remains unconfirmed.
|
|
18
|
+
- AI chat preserves the edited note and includes its permitted tree, tags, and cached URL titles. Search redaction and cloud privacy restrictions apply to every node; blocked selections expose only their availability reason.
|
|
19
|
+
- Added on-demand AI help and menu actions, privacy previews, and Copy Response throughout assistant message bubbles. OpenAI is the supported inference provider.
|
|
20
|
+
- LLM regressions use current production prompts, default to five trials with cache-aware parallel scheduling, and can run only cases affected by prompt or skill changes.
|
|
21
|
+
- Improved Grammarly edit preservation and search suggestions that match the complete active clause.
|
|
22
|
+
|
|
15
23
|
## Changes in 0.6.3
|
|
16
24
|
|
|
17
25
|
- Restored HTTPS connection reuse and aligned the pending accept queue with the existing worker capacity, so a browser’s six-connection startup burst is admitted.
|
|
@@ -177,6 +185,18 @@ METALIST_HOST=192.168.1.20 metalist
|
|
|
177
185
|
```
|
|
178
186
|
On a fresh machine, that first launch also creates the default TLS cert pair automatically. Then open either `http://192.168.1.20:8000` or `https://192.168.1.20:8443` from the other machine.
|
|
179
187
|
|
|
188
|
+
Starting with 0.7.1, an explicit `METALIST_HOST` or `METALIST_ALLOWED_HOSTS`
|
|
189
|
+
configuration is saved in `~/MetaList/network-settings.json` (under
|
|
190
|
+
`METALIST_DATA_DIRECTORY` when overridden). Subsequent source launches, plain
|
|
191
|
+
`metalist` launches, and updates reuse it. Environment values override and update
|
|
192
|
+
the corresponding saved settings. This file stores only the bind address and
|
|
193
|
+
allowed hosts; namespace ports remain in their launch profiles, and shell access
|
|
194
|
+
still requires `--enable-shell` on each launch. Invalid settings stop startup
|
|
195
|
+
with an error. Fresh installations continue to bind to localhost by default.
|
|
196
|
+
To switch back to local-only access, run `METALIST_HOST=127.0.0.1 metalist` once.
|
|
197
|
+
Older installed versions do not read this file; keep supplying their LAN settings
|
|
198
|
+
until upgrading to 0.7.1 or later.
|
|
199
|
+
|
|
180
200
|
To keep `@shell` available on the host laptop while allowing another laptop to
|
|
181
201
|
use normal MetaList features, bind both interfaces and explicitly allow the LAN
|
|
182
202
|
address:
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import asyncio
|
|
6
5
|
import json
|
|
7
6
|
import math
|
|
8
7
|
from collections.abc import AsyncIterator
|
|
@@ -27,7 +26,6 @@ from app.services.agent.cloud_privacy import cloud_privacy_evaluator
|
|
|
27
26
|
from app.services.agent.cloud_privacy import resolve_cloud_privacy_boundary
|
|
28
27
|
from app.services.agent.inference import InferenceAdapter
|
|
29
28
|
from app.services.agent.model_policy import SingleModelPolicy
|
|
30
|
-
from app.services.agent.ollama_inference import OllamaInferenceAdapter
|
|
31
29
|
from app.services.agent.openai_inference import OPENAI_API_BASE_URL
|
|
32
30
|
from app.services.agent.openai_inference import OPENAI_MODELS
|
|
33
31
|
from app.services.agent.openai_inference import OpenAIInferenceAdapter
|
|
@@ -50,15 +48,10 @@ from app.services.agent.skill_settings import resolve_agent_skill_set
|
|
|
50
48
|
from app.services.agent.token_estimation import estimate_input_tokens
|
|
51
49
|
from app.services.agent.tools import read_only_agent_tools
|
|
52
50
|
from app.services.agent.trace import agent_trace_store
|
|
51
|
+
from app.services.agent.menu_actions import MenuResult, menu_action_store
|
|
53
52
|
from app.services.client_state_service import load_client_preferences
|
|
54
53
|
from app.services.markdown_rendering import render_markdown_to_html
|
|
55
|
-
from app.services.managed_ollama_runtime import ManagedOllamaRuntimeError
|
|
56
|
-
from app.services.managed_ollama_runtime import managed_ollama_runtime
|
|
57
54
|
from app.services.note_store import store as note_store
|
|
58
|
-
from app.services.ollama_provider import OllamaProviderError
|
|
59
|
-
from app.services.ollama_provider import ollama_provider
|
|
60
|
-
from app.services.ollama_provider import resolve_ollama_think_value
|
|
61
|
-
from app.services.ollama_provider import validate_ollama_model
|
|
62
55
|
from app.services.openai_credentials import OpenAICredentialInputError
|
|
63
56
|
from app.services.openai_credentials import openai_credential_store
|
|
64
57
|
from app.services.openai_credentials import validate_openai_api_key
|
|
@@ -89,17 +82,10 @@ def _agent_runtime(*, inference: InferenceAdapter) -> AgentRuntime:
|
|
|
89
82
|
)
|
|
90
83
|
|
|
91
84
|
|
|
92
|
-
agent_runtime = _agent_runtime(
|
|
93
|
-
inference=OllamaInferenceAdapter(provider=ollama_provider)
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
85
|
class AiModelsRequest(BaseModel):
|
|
100
86
|
model_config = ConfigDict(extra="forbid")
|
|
101
87
|
|
|
102
|
-
provider: Literal["
|
|
88
|
+
provider: Literal["openai"]
|
|
103
89
|
|
|
104
90
|
|
|
105
91
|
class AiModelsResponse(BaseModel):
|
|
@@ -128,7 +114,7 @@ class OpenAICostResponse(BaseModel):
|
|
|
128
114
|
class CloudPrivacyPreviewRequest(BaseModel):
|
|
129
115
|
model_config = ConfigDict(extra="forbid")
|
|
130
116
|
|
|
131
|
-
provider: Literal["
|
|
117
|
+
provider: Literal["openai"]
|
|
132
118
|
note_ids: list[str] = Field(..., max_length=20_000)
|
|
133
119
|
|
|
134
120
|
@field_validator("note_ids")
|
|
@@ -163,27 +149,16 @@ class AiPromptDefaultsResponse(BaseModel):
|
|
|
163
149
|
skills: list[AiSkillDefaultResponse]
|
|
164
150
|
|
|
165
151
|
|
|
166
|
-
class AiModelPullRequest(BaseModel):
|
|
167
|
-
model_config = ConfigDict(extra="forbid")
|
|
168
|
-
|
|
169
|
-
provider: Literal["ollama"]
|
|
170
|
-
model: str
|
|
171
|
-
|
|
172
|
-
@field_validator("model")
|
|
173
|
-
@classmethod
|
|
174
|
-
def validate_model(cls, value: str) -> str:
|
|
175
|
-
return validate_ollama_model(value)
|
|
176
|
-
|
|
177
|
-
|
|
178
152
|
class AiChatRequest(BaseModel):
|
|
179
153
|
model_config = ConfigDict(extra="forbid")
|
|
180
154
|
|
|
181
|
-
provider: Literal["
|
|
155
|
+
provider: Literal["openai"]
|
|
182
156
|
model: str
|
|
183
157
|
thinking_level: Literal["off", "low", "medium", "high"]
|
|
184
158
|
show_diagnostics: bool
|
|
185
159
|
message: str = Field(..., max_length=32_000)
|
|
186
160
|
scope: AgentScopeDescriptor
|
|
161
|
+
selected_note_id: str = Field(..., max_length=128, pattern=r"^(?:\S+)?$")
|
|
187
162
|
|
|
188
163
|
@field_validator("model")
|
|
189
164
|
@classmethod
|
|
@@ -202,14 +177,7 @@ class AiChatRequest(BaseModel):
|
|
|
202
177
|
|
|
203
178
|
@model_validator(mode="after")
|
|
204
179
|
def validate_thinking_level_for_model(self) -> Self:
|
|
205
|
-
|
|
206
|
-
validate_ollama_model(self.model)
|
|
207
|
-
resolve_ollama_think_value(
|
|
208
|
-
model=self.model,
|
|
209
|
-
thinking_level=self.thinking_level,
|
|
210
|
-
)
|
|
211
|
-
else:
|
|
212
|
-
validate_openai_model(self.model)
|
|
180
|
+
validate_openai_model(self.model)
|
|
213
181
|
return self
|
|
214
182
|
|
|
215
183
|
|
|
@@ -239,7 +207,7 @@ class AiChatMessage(BaseModel):
|
|
|
239
207
|
rendered_thinking: str
|
|
240
208
|
status: Literal["complete", "streaming", "error"]
|
|
241
209
|
error: str
|
|
242
|
-
provider: Literal["
|
|
210
|
+
provider: Literal["openai"]
|
|
243
211
|
model: str
|
|
244
212
|
activities: list[AiChatActivity]
|
|
245
213
|
|
|
@@ -308,15 +276,8 @@ async def list_ai_models(
|
|
|
308
276
|
payload: AiModelsRequest,
|
|
309
277
|
token: Annotated[str, Depends(require_request_auth_token)],
|
|
310
278
|
) -> AiModelsResponse:
|
|
311
|
-
del token
|
|
312
|
-
|
|
313
|
-
return AiModelsResponse(models=list(OPENAI_MODELS))
|
|
314
|
-
try:
|
|
315
|
-
runtime_info = await asyncio.to_thread(managed_ollama_runtime.ensure_running)
|
|
316
|
-
models = await ollama_provider.list_models(base_url=runtime_info.base_url)
|
|
317
|
-
except (ManagedOllamaRuntimeError, OllamaProviderError) as exc:
|
|
318
|
-
raise HTTPException(status_code=502, detail=str(exc)) from exc
|
|
319
|
-
return AiModelsResponse(models=models)
|
|
279
|
+
del token, payload
|
|
280
|
+
return AiModelsResponse(models=list(OPENAI_MODELS))
|
|
320
281
|
|
|
321
282
|
|
|
322
283
|
@router.get(
|
|
@@ -476,38 +437,6 @@ def preview_cloud_privacy(
|
|
|
476
437
|
)
|
|
477
438
|
|
|
478
439
|
|
|
479
|
-
@router.post("/models/pull")
|
|
480
|
-
@transactional_route
|
|
481
|
-
def pull_ai_model(
|
|
482
|
-
payload: AiModelPullRequest,
|
|
483
|
-
token: Annotated[str, Depends(require_request_auth_token)],
|
|
484
|
-
) -> StreamingResponse:
|
|
485
|
-
del token
|
|
486
|
-
|
|
487
|
-
async def stream_events() -> AsyncIterator[str]:
|
|
488
|
-
try:
|
|
489
|
-
runtime_info = await asyncio.to_thread(managed_ollama_runtime.ensure_running)
|
|
490
|
-
async for event in ollama_provider.stream_pull(
|
|
491
|
-
base_url=runtime_info.base_url,
|
|
492
|
-
model=payload.model,
|
|
493
|
-
):
|
|
494
|
-
yield f"{json.dumps(event, separators=(',', ':'))}\n"
|
|
495
|
-
# lint: allow-PY001 rationale="pull errors must be delivered after response headers are sent"
|
|
496
|
-
except (ManagedOllamaRuntimeError, OllamaProviderError) as exc:
|
|
497
|
-
error_event = {"type": "error", "message": str(exc)}
|
|
498
|
-
yield f"{json.dumps(error_event, separators=(',', ':'))}\n"
|
|
499
|
-
|
|
500
|
-
return StreamingResponse(
|
|
501
|
-
stream_events(),
|
|
502
|
-
media_type="application/x-ndjson",
|
|
503
|
-
headers={
|
|
504
|
-
"X-Accel-Buffering": "no",
|
|
505
|
-
"Cache-Control": "no-store",
|
|
506
|
-
"Content-Encoding": "identity",
|
|
507
|
-
},
|
|
508
|
-
)
|
|
509
|
-
|
|
510
|
-
|
|
511
440
|
@router.get("/session", response_model=AiSessionResponse)
|
|
512
441
|
def get_ai_session(
|
|
513
442
|
response: Response,
|
|
@@ -589,6 +518,17 @@ def get_ai_debug_snapshot(
|
|
|
589
518
|
)
|
|
590
519
|
|
|
591
520
|
|
|
521
|
+
@router.get("/history")
|
|
522
|
+
def get_ai_history(
|
|
523
|
+
response: Response,
|
|
524
|
+
token: Annotated[str, Depends(require_request_auth_token)],
|
|
525
|
+
) -> list:
|
|
526
|
+
response.headers["Cache-Control"] = "no-store"
|
|
527
|
+
return agent_trace_store.export_history(
|
|
528
|
+
session_key=token_service.get_session_key(token)
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
592
532
|
@router.put("/debug", response_model=AiDebugSnapshotResponse)
|
|
593
533
|
@transactional_route
|
|
594
534
|
def put_ai_debug_details(
|
|
@@ -666,21 +606,19 @@ def stream_ai_chat(
|
|
|
666
606
|
token: Annotated[str, Depends(require_request_auth_token)],
|
|
667
607
|
) -> StreamingResponse:
|
|
668
608
|
session_key = token_service.get_session_key(token)
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
status_code=409,
|
|
678
|
-
detail="OpenAI API key is not configured",
|
|
679
|
-
)
|
|
680
|
-
openai_api_key = openai_credential_store.resolve(
|
|
681
|
-
token=token,
|
|
682
|
-
session_key=session_key,
|
|
609
|
+
credential_status = openai_credential_store.status(
|
|
610
|
+
token=token,
|
|
611
|
+
session_key=session_key,
|
|
612
|
+
)
|
|
613
|
+
if not credential_status.configured:
|
|
614
|
+
raise HTTPException(
|
|
615
|
+
status_code=409,
|
|
616
|
+
detail="OpenAI API key is not configured",
|
|
683
617
|
)
|
|
618
|
+
openai_api_key = openai_credential_store.resolve(
|
|
619
|
+
token=token,
|
|
620
|
+
session_key=session_key,
|
|
621
|
+
)
|
|
684
622
|
preferences = load_client_preferences(token=token)
|
|
685
623
|
prompts = resolve_agent_prompt_set(preferences=preferences)
|
|
686
624
|
skills = resolve_agent_skill_set(preferences=preferences)
|
|
@@ -704,6 +642,11 @@ def stream_ai_chat(
|
|
|
704
642
|
authoritative_sort_mode = tab_state_store.get_sort_mode(
|
|
705
643
|
tab_id=payload.scope.scope_tab_id
|
|
706
644
|
)
|
|
645
|
+
active_search_query = authoritative_search_query
|
|
646
|
+
active_sort_mode = authoritative_sort_mode
|
|
647
|
+
if payload.selected_note_id and payload.scope.active_tab_id != payload.scope.scope_tab_id:
|
|
648
|
+
active_search_query = tab_state_store.get_search_query(tab_id=authoritative_active_tab_id)
|
|
649
|
+
active_sort_mode = tab_state_store.get_sort_mode(tab_id=authoritative_active_tab_id)
|
|
707
650
|
frozen_scope = scoped_search_snapshot_factory.freeze(
|
|
708
651
|
descriptor=payload.scope,
|
|
709
652
|
authoritative_search_query=authoritative_search_query,
|
|
@@ -711,6 +654,9 @@ def stream_ai_chat(
|
|
|
711
654
|
run_id=str(uuid4()),
|
|
712
655
|
session_key=session_key,
|
|
713
656
|
privacy_boundary=privacy_boundary,
|
|
657
|
+
selected_note_id=payload.selected_note_id,
|
|
658
|
+
authoritative_active_search_query=active_search_query,
|
|
659
|
+
authoritative_active_sort_mode=active_sort_mode,
|
|
714
660
|
)
|
|
715
661
|
tagging_run = TaggingRun(token=token, snapshot=frozen_scope, preferences=preferences, sync_uuid=get_current_sync_uuid(),
|
|
716
662
|
batch_tokens=resolve_tagging_batch_tokens(preferences, payload.provider))
|
|
@@ -758,18 +704,9 @@ async def _stream_runtime_events(
|
|
|
758
704
|
action, start_label = 'provider_runtime', 'Connecting to OpenAI API'
|
|
759
705
|
ready_label = 'OpenAI API ready · 1,050,000-token context'
|
|
760
706
|
base_url = OPENAI_API_BASE_URL
|
|
761
|
-
|
|
762
|
-
action = 'ollama_runtime'
|
|
763
|
-
start_label = 'Starting MetaList-managed Ollama · 32,768-token context'
|
|
764
|
-
runtime = agent_runtime
|
|
765
|
-
else:
|
|
766
|
-
runtime = _agent_runtime(inference=OpenAIInferenceAdapter(api_key=openai_api_key, cost_tracker=openai_cost_tracker))
|
|
707
|
+
runtime = _agent_runtime(inference=OpenAIInferenceAdapter(api_key=openai_api_key, cost_tracker=openai_cost_tracker))
|
|
767
708
|
yield dict(type='action_status', action=action, status='started', label=start_label,
|
|
768
709
|
approx_input_tokens=initial_input_tokens, output_tokens_received=0, duration_ms=0.0)
|
|
769
|
-
if payload.provider == 'ollama':
|
|
770
|
-
runtime_info = await asyncio.to_thread(managed_ollama_runtime.ensure_running)
|
|
771
|
-
base_url = runtime_info.base_url
|
|
772
|
-
ready_label = f'MetaList-managed Ollama ready · {runtime_info.context_tokens:,}-token context'
|
|
773
710
|
yield dict(type='action_status', action=action, status='completed', label=ready_label,
|
|
774
711
|
approx_input_tokens=initial_input_tokens, output_tokens_received=0, duration_ms=0.0)
|
|
775
712
|
events = runtime.stream_scoped(session_key=session_key, base_url=base_url,
|
|
@@ -783,6 +720,18 @@ async def _stream_runtime_events(
|
|
|
783
720
|
await events.aclose()
|
|
784
721
|
|
|
785
722
|
|
|
723
|
+
@router.post("/menu-result")
|
|
724
|
+
@transactional_route
|
|
725
|
+
async def acknowledge_menu_result(payload: MenuResult, token: Annotated[str, Depends(require_request_auth_token)]):
|
|
726
|
+
# lint: allow-PY001 rationale="browser acknowledgments can be stale or belong to another session"
|
|
727
|
+
try:
|
|
728
|
+
menu_action_store.acknowledge(session_key=token_service.get_session_key(token), result=payload)
|
|
729
|
+
# lint: allow-PY001 rationale="reject invalid external menu acknowledgment with a conflict response"
|
|
730
|
+
except ValueError as exc:
|
|
731
|
+
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
732
|
+
return {"acknowledged": True}
|
|
733
|
+
|
|
734
|
+
|
|
786
735
|
class BulkAnswerRequest(BaseModel):
|
|
787
736
|
model_config = ConfigDict(extra="forbid")
|
|
788
737
|
question_id: str = Field(..., min_length=1)
|
|
@@ -78,9 +78,9 @@ CAPTURE_BOUNDARIES = {
|
|
|
78
78
|
# Translate explicitly validated domain input/resource rejection.
|
|
79
79
|
'app/main.py:namespace_renamed_page:job_record_capture': ('NamespaceInputRejected', 'FileNotFoundError'),
|
|
80
80
|
# Parse external host, URL, IP or date input at the named boundary.
|
|
81
|
-
'app/security/
|
|
81
|
+
'app/security/request_hosts.py:_normalize_configured_hostname:normalize_capture': ('ValueError',),
|
|
82
82
|
# Parse external host, URL, IP or date input at the named boundary.
|
|
83
|
-
'app/security/
|
|
83
|
+
'app/security/request_hosts.py:_normalize_hostname:ip_capture': ('ValueError',),
|
|
84
84
|
# Parse external host, URL, IP or date input at the named boundary.
|
|
85
85
|
'app/security/request_boundary.py:_parse_host_header:parse_capture': ('ValueError',),
|
|
86
86
|
# Parse external host, URL, IP or date input at the named boundary.
|
|
@@ -112,16 +112,6 @@ CAPTURE_BOUNDARIES = {
|
|
|
112
112
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
113
113
|
'app/services/link_titles.py:fetch_link_title:target_capture': ('_LinkTitleTargetRejected',),
|
|
114
114
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
115
|
-
'app/services/managed_ollama_runtime.py:_acquire_startup_lock:lock_capture': ('FileExistsError',),
|
|
116
|
-
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
117
|
-
'app/services/managed_ollama_runtime.py:_is_process_running:process_capture': ('ProcessLookupError', 'PermissionError'),
|
|
118
|
-
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
119
|
-
'app/services/managed_ollama_runtime.py:_probe_ollama_version:probe_capture': ('HTTPError', 'JSONDecodeError'),
|
|
120
|
-
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
121
|
-
'app/services/managed_ollama_runtime.py:_remove_stale_lock:missing_capture': ('FileNotFoundError',),
|
|
122
|
-
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
123
|
-
'app/services/managed_ollama_runtime.py:_remove_stale_lock:read_capture': ('FileNotFoundError',),
|
|
124
|
-
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
125
115
|
'app/services/namespace_deletion_worker.py:_is_process_running:kill_capture': ('ProcessLookupError', 'PermissionError'),
|
|
126
116
|
# Handle expected external I/O, provider, image or LaTeX parsing failure.
|
|
127
117
|
'app/services/namespace_deletion_worker.py:_send_signal_if_running:signal_capture': ('ProcessLookupError',),
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Machine network preferences shared by source and installed entrypoints.
|
|
2
|
+
|
|
3
|
+
Only an explicit bind address/allowed-host configuration opts into persistence.
|
|
4
|
+
Namespace ports, shell capability, credentials, and backups are not stored here.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from collections.abc import MutableMapping
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from uuid import uuid4
|
|
13
|
+
|
|
14
|
+
from app.data_directory import resolve_data_directory
|
|
15
|
+
from app.security.request_hosts import resolve_allowed_request_hosts
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_NETWORK_ENVIRONMENT_KEYS = frozenset({'METALIST_HOST', 'METALIST_ALLOWED_HOSTS'})
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _validate_network_environment(environment: object) -> dict[str, str]:
|
|
22
|
+
if not isinstance(environment, dict) or not environment.keys() <= _NETWORK_ENVIRONMENT_KEYS:
|
|
23
|
+
raise RuntimeError('Network settings must contain only bind-address and allowed-host preferences')
|
|
24
|
+
if any(not isinstance(value, str) for value in environment.values()):
|
|
25
|
+
raise RuntimeError('Network settings values must be strings')
|
|
26
|
+
resolve_allowed_request_hosts(environ=environment)
|
|
27
|
+
return dict(environment)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _read_network_settings(path: Path) -> dict[str, str]:
|
|
31
|
+
if not path.exists():
|
|
32
|
+
return {}
|
|
33
|
+
payload = json.loads(path.read_text(encoding='utf-8'))
|
|
34
|
+
if (not isinstance(payload, dict) or set(payload) != {'version', 'environment'}
|
|
35
|
+
or type(payload['version']) is not int or payload['version'] != 1):
|
|
36
|
+
raise RuntimeError(f'Invalid network settings file: {path}')
|
|
37
|
+
return _validate_network_environment(payload['environment'])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _write_network_settings(path: Path, environment: dict[str, str]) -> None:
|
|
41
|
+
assert path.name == 'network-settings.json'
|
|
42
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
43
|
+
temporary = path.with_name(f'.network-settings-{uuid4().hex}.tmp')
|
|
44
|
+
try:
|
|
45
|
+
with temporary.open('x', encoding='utf-8') as stream:
|
|
46
|
+
json.dump({'version': 1, 'environment': environment}, stream, indent=2)
|
|
47
|
+
stream.write('\n')
|
|
48
|
+
os.replace(temporary, path)
|
|
49
|
+
finally:
|
|
50
|
+
temporary.unlink(missing_ok=True)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def apply_network_settings(*, environ: MutableMapping[str, str], persist: bool) -> None:
|
|
54
|
+
path = resolve_data_directory(environ=environ) / 'network-settings.json'
|
|
55
|
+
saved = _read_network_settings(path)
|
|
56
|
+
configured = {key: environ[key] for key in _NETWORK_ENVIRONMENT_KEYS if key in environ}
|
|
57
|
+
effective = _validate_network_environment(saved | configured)
|
|
58
|
+
if persist and effective != saved:
|
|
59
|
+
_write_network_settings(path, effective)
|
|
60
|
+
print(f'[startup] Saved network settings: {path}', flush=True)
|
|
61
|
+
environ.update(effective)
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from collections.abc import Mapping
|
|
4
3
|
from dataclasses import dataclass
|
|
5
|
-
import ipaddress
|
|
6
|
-
import re
|
|
7
4
|
from urllib.parse import urlsplit
|
|
8
5
|
|
|
9
6
|
from fastapi import Request
|
|
@@ -12,14 +9,10 @@ from starlette.middleware.base import BaseHTTPMiddleware
|
|
|
12
9
|
|
|
13
10
|
from app.api.request_auth import AUTH_COOKIE_NAME
|
|
14
11
|
from app.services.exception_capture import CapturedExceptionContext
|
|
12
|
+
from app.security.request_hosts import _normalize_hostname, resolve_allowed_request_hosts
|
|
15
13
|
|
|
16
14
|
|
|
17
|
-
_LOOPBACK_REQUEST_HOSTS = frozenset({"127.0.0.1", "::1", "localhost"})
|
|
18
|
-
_WILDCARD_BIND_HOSTS = frozenset({"0.0.0.0", "::"})
|
|
19
15
|
_SAFE_METHODS = frozenset({"GET", "HEAD", "OPTIONS"})
|
|
20
|
-
_DNS_HOSTNAME_PATTERN = re.compile(
|
|
21
|
-
r"^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$"
|
|
22
|
-
)
|
|
23
16
|
|
|
24
17
|
|
|
25
18
|
@dataclass(frozen=True)
|
|
@@ -28,72 +21,6 @@ class RequestBoundaryRejection:
|
|
|
28
21
|
detail: str
|
|
29
22
|
|
|
30
23
|
|
|
31
|
-
def _normalize_hostname(*, hostname: str, context: str) -> str:
|
|
32
|
-
normalized = hostname.strip().casefold().rstrip(".")
|
|
33
|
-
if normalized == "":
|
|
34
|
-
raise ValueError(f"{context} hostname must not be empty")
|
|
35
|
-
|
|
36
|
-
ip_capture = CapturedExceptionContext(ValueError, boundary='app/security/request_boundary.py:_normalize_hostname:ip_capture')
|
|
37
|
-
parsed_ip: ipaddress._BaseAddress | None = None
|
|
38
|
-
with ip_capture:
|
|
39
|
-
parsed_ip = ipaddress.ip_address(normalized)
|
|
40
|
-
if ip_capture.captured_exception is None:
|
|
41
|
-
if parsed_ip is None:
|
|
42
|
-
raise RuntimeError("IP parser returned no address")
|
|
43
|
-
return parsed_ip.compressed.casefold()
|
|
44
|
-
|
|
45
|
-
if _DNS_HOSTNAME_PATTERN.fullmatch(normalized) is None:
|
|
46
|
-
raise ValueError(f"{context} contains an invalid hostname: {hostname!r}")
|
|
47
|
-
return normalized
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def _normalize_configured_hostname(*, raw_value: str) -> str:
|
|
51
|
-
value = raw_value.strip()
|
|
52
|
-
if value == "":
|
|
53
|
-
raise RuntimeError("METALIST_ALLOWED_HOSTS contains an empty entry")
|
|
54
|
-
if value == "*":
|
|
55
|
-
raise RuntimeError("METALIST_ALLOWED_HOSTS must not contain '*'")
|
|
56
|
-
if "://" in value or "/" in value or "@" in value:
|
|
57
|
-
raise RuntimeError(
|
|
58
|
-
"METALIST_ALLOWED_HOSTS entries must be hostnames without schemes, ports, or paths"
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
unbracketed_value = value
|
|
62
|
-
if value.startswith("[") and value.endswith("]"):
|
|
63
|
-
unbracketed_value = value[1:-1]
|
|
64
|
-
normalize_capture = CapturedExceptionContext(ValueError, boundary='app/security/request_boundary.py:_normalize_configured_hostname:normalize_capture')
|
|
65
|
-
normalized_hostname: str | None = None
|
|
66
|
-
with normalize_capture:
|
|
67
|
-
normalized_hostname = _normalize_hostname(
|
|
68
|
-
hostname=unbracketed_value,
|
|
69
|
-
context="METALIST_ALLOWED_HOSTS",
|
|
70
|
-
)
|
|
71
|
-
if normalize_capture.captured_exception is not None:
|
|
72
|
-
exc = normalize_capture.captured_exception
|
|
73
|
-
raise RuntimeError(str(exc)) from exc
|
|
74
|
-
if normalized_hostname is None:
|
|
75
|
-
raise RuntimeError("METALIST_ALLOWED_HOSTS parser returned no hostname")
|
|
76
|
-
return normalized_hostname
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def resolve_allowed_request_hosts(*, environ: Mapping[str, str]) -> frozenset[str]:
|
|
80
|
-
allowed_hosts = set(_LOOPBACK_REQUEST_HOSTS)
|
|
81
|
-
bind_host = environ.get("METALIST_HOST", "127.0.0.1").strip()
|
|
82
|
-
if bind_host == "":
|
|
83
|
-
raise RuntimeError("METALIST_HOST must not be empty")
|
|
84
|
-
normalized_bind_host = _normalize_configured_hostname(raw_value=bind_host)
|
|
85
|
-
if normalized_bind_host not in _WILDCARD_BIND_HOSTS:
|
|
86
|
-
allowed_hosts.add(normalized_bind_host)
|
|
87
|
-
|
|
88
|
-
configured_hosts = environ.get("METALIST_ALLOWED_HOSTS")
|
|
89
|
-
if configured_hosts is not None:
|
|
90
|
-
if configured_hosts.strip() == "":
|
|
91
|
-
raise RuntimeError("METALIST_ALLOWED_HOSTS must not be empty when set")
|
|
92
|
-
for raw_host in configured_hosts.split(","):
|
|
93
|
-
allowed_hosts.add(_normalize_configured_hostname(raw_value=raw_host))
|
|
94
|
-
return frozenset(allowed_hosts)
|
|
95
|
-
|
|
96
|
-
|
|
97
24
|
def _parse_host_header(host_header: str) -> tuple[str, int | None] | None:
|
|
98
25
|
raw_host = host_header.strip()
|
|
99
26
|
if raw_host == "":
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Host validation shared by early launch settings and HTTP request checks."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
import ipaddress
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
from app.services.exception_capture import CapturedExceptionContext
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
_LOOPBACK_REQUEST_HOSTS = frozenset({"127.0.0.1", "::1", "localhost"})
|
|
12
|
+
_WILDCARD_BIND_HOSTS = frozenset({"0.0.0.0", "::"})
|
|
13
|
+
_DNS_HOSTNAME_PATTERN = re.compile(
|
|
14
|
+
r"^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _normalize_hostname(*, hostname: str, context: str) -> str:
|
|
19
|
+
normalized = hostname.strip().casefold().rstrip(".")
|
|
20
|
+
if normalized == "":
|
|
21
|
+
raise ValueError(f"{context} hostname must not be empty")
|
|
22
|
+
|
|
23
|
+
ip_capture = CapturedExceptionContext(ValueError, boundary='app/security/request_hosts.py:_normalize_hostname:ip_capture')
|
|
24
|
+
parsed_ip: ipaddress._BaseAddress | None = None
|
|
25
|
+
with ip_capture:
|
|
26
|
+
parsed_ip = ipaddress.ip_address(normalized)
|
|
27
|
+
if ip_capture.captured_exception is None:
|
|
28
|
+
if parsed_ip is None:
|
|
29
|
+
raise RuntimeError("IP parser returned no address")
|
|
30
|
+
return parsed_ip.compressed.casefold()
|
|
31
|
+
|
|
32
|
+
if _DNS_HOSTNAME_PATTERN.fullmatch(normalized) is None:
|
|
33
|
+
raise ValueError(f"{context} contains an invalid hostname: {hostname!r}")
|
|
34
|
+
return normalized
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _normalize_configured_hostname(*, raw_value: str) -> str:
|
|
38
|
+
value = raw_value.strip()
|
|
39
|
+
if value == "":
|
|
40
|
+
raise RuntimeError("METALIST_ALLOWED_HOSTS contains an empty entry")
|
|
41
|
+
if value == "*":
|
|
42
|
+
raise RuntimeError("METALIST_ALLOWED_HOSTS must not contain '*'")
|
|
43
|
+
if "://" in value or "/" in value or "@" in value:
|
|
44
|
+
raise RuntimeError(
|
|
45
|
+
"METALIST_ALLOWED_HOSTS entries must be hostnames without schemes, ports, or paths"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
unbracketed_value = value
|
|
49
|
+
if value.startswith("[") and value.endswith("]"):
|
|
50
|
+
unbracketed_value = value[1:-1]
|
|
51
|
+
normalize_capture = CapturedExceptionContext(ValueError, boundary='app/security/request_hosts.py:_normalize_configured_hostname:normalize_capture')
|
|
52
|
+
normalized_hostname: str | None = None
|
|
53
|
+
with normalize_capture:
|
|
54
|
+
normalized_hostname = _normalize_hostname(
|
|
55
|
+
hostname=unbracketed_value,
|
|
56
|
+
context="METALIST_ALLOWED_HOSTS",
|
|
57
|
+
)
|
|
58
|
+
if normalize_capture.captured_exception is not None:
|
|
59
|
+
exc = normalize_capture.captured_exception
|
|
60
|
+
raise RuntimeError(str(exc)) from exc
|
|
61
|
+
if normalized_hostname is None:
|
|
62
|
+
raise RuntimeError("METALIST_ALLOWED_HOSTS parser returned no hostname")
|
|
63
|
+
return normalized_hostname
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def resolve_allowed_request_hosts(*, environ: Mapping[str, str]) -> frozenset[str]:
|
|
67
|
+
allowed_hosts = set(_LOOPBACK_REQUEST_HOSTS)
|
|
68
|
+
bind_host = environ.get("METALIST_HOST", "127.0.0.1").strip()
|
|
69
|
+
if bind_host == "":
|
|
70
|
+
raise RuntimeError("METALIST_HOST must not be empty")
|
|
71
|
+
normalized_bind_host = _normalize_configured_hostname(raw_value=bind_host)
|
|
72
|
+
if normalized_bind_host not in _WILDCARD_BIND_HOSTS:
|
|
73
|
+
allowed_hosts.add(normalized_bind_host)
|
|
74
|
+
|
|
75
|
+
configured_hosts = environ.get("METALIST_ALLOWED_HOSTS")
|
|
76
|
+
if configured_hosts is not None:
|
|
77
|
+
if configured_hosts.strip() == "":
|
|
78
|
+
raise RuntimeError("METALIST_ALLOWED_HOSTS must not be empty when set")
|
|
79
|
+
for raw_host in configured_hosts.split(","):
|
|
80
|
+
allowed_hosts.add(_normalize_configured_hostname(raw_value=raw_host))
|
|
81
|
+
return frozenset(allowed_hosts)
|
|
82
|
+
|
|
83
|
+
|