marvisx-cli 0.1.0__py3-none-any.whl
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.
- core/api/__init__.py +0 -0
- core/api/agents/__init__.py +0 -0
- core/api/agents/session_health.py +59 -0
- core/api/agents/session_manager.py +206 -0
- core/api/bin/marvisx-state-hook.py +182 -0
- core/api/config.py +533 -0
- core/api/db.py +1516 -0
- core/api/dependencies/__init__.py +0 -0
- core/api/dependencies/tenant.py +34 -0
- core/api/main.py +1641 -0
- core/api/mcp/__init__.py +8 -0
- core/api/mcp/_adapter.py +184 -0
- core/api/mcp/server.py +58 -0
- core/api/mcp/tools/__init__.py +59 -0
- core/api/mcp/tools/brain.py +599 -0
- core/api/mcp/tools/graph.py +380 -0
- core/api/mcp/tools/handoffs.py +112 -0
- core/api/mcp/tools/ingest.py +326 -0
- core/api/mcp/tools/learnings.py +144 -0
- core/api/mcp/tools/projects.py +99 -0
- core/api/mcp/tools/pull_requests.py +173 -0
- core/api/mcp/tools/safety.py +111 -0
- core/api/mcp/tools/search.py +79 -0
- core/api/mcp/tools/tasks.py +258 -0
- core/api/middleware/__init__.py +0 -0
- core/api/middleware/tool_call_audit.py +111 -0
- core/api/models/__init__.py +346 -0
- core/api/models/auth.py +48 -0
- core/api/models/brain.py +1006 -0
- core/api/models/common.py +76 -0
- core/api/models/costs.py +91 -0
- core/api/models/graph.py +66 -0
- core/api/models/graph_cosmo.py +125 -0
- core/api/models/graph_pr_impact.py +257 -0
- core/api/models/graph_ux.py +141 -0
- core/api/models/inbox.py +230 -0
- core/api/models/ingest_keys.py +108 -0
- core/api/models/kg.py +41 -0
- core/api/models/llm_config.py +56 -0
- core/api/models/monitoring.py +234 -0
- core/api/models/projects.py +161 -0
- core/api/models/search.py +42 -0
- core/api/models/sessions.py +322 -0
- core/api/models/tasks.py +184 -0
- core/api/models/teams.py +63 -0
- core/api/models/users.py +184 -0
- core/api/observability/__init__.py +0 -0
- core/api/observability/tracing.py +92 -0
- core/api/paths.py +26 -0
- core/api/rate_limit.py +24 -0
- core/api/rbac.py +112 -0
- core/api/routers/__init__.py +0 -0
- core/api/routers/_adapter.py +24 -0
- core/api/routers/admin_pr_impact.py +230 -0
- core/api/routers/admin_settings.py +147 -0
- core/api/routers/agent.py +1079 -0
- core/api/routers/agent_tokens.py +276 -0
- core/api/routers/app_settings.py +112 -0
- core/api/routers/audit.py +89 -0
- core/api/routers/auth.py +586 -0
- core/api/routers/bench.py +161 -0
- core/api/routers/brain.py +881 -0
- core/api/routers/brain_directions.py +527 -0
- core/api/routers/ci_checks.py +140 -0
- core/api/routers/comments.py +273 -0
- core/api/routers/costs.py +148 -0
- core/api/routers/docs_coverage.py +217 -0
- core/api/routers/docs_governance.py +63 -0
- core/api/routers/documents.py +318 -0
- core/api/routers/files.py +163 -0
- core/api/routers/finder.py +987 -0
- core/api/routers/graph.py +836 -0
- core/api/routers/handoffs.py +156 -0
- core/api/routers/inbox.py +496 -0
- core/api/routers/ingest_api_keys.py +205 -0
- core/api/routers/ingest_triage.py +1227 -0
- core/api/routers/judge.py +306 -0
- core/api/routers/kg.py +336 -0
- core/api/routers/learnings.py +253 -0
- core/api/routers/llm_config.py +130 -0
- core/api/routers/monitoring.py +347 -0
- core/api/routers/notifications.py +125 -0
- core/api/routers/pr_impact.py +315 -0
- core/api/routers/projects.py +1061 -0
- core/api/routers/pull_requests.py +312 -0
- core/api/routers/push.py +67 -0
- core/api/routers/raci.py +228 -0
- core/api/routers/search.py +125 -0
- core/api/routers/sessions.py +3100 -0
- core/api/routers/settings.py +90 -0
- core/api/routers/share_repo.py +68 -0
- core/api/routers/status_updates.py +96 -0
- core/api/routers/tags.py +45 -0
- core/api/routers/tasks.py +526 -0
- core/api/routers/teams.py +425 -0
- core/api/routers/terminal.py +105 -0
- core/api/routers/users.py +331 -0
- core/api/routers/webhooks.py +330 -0
- core/api/runtime_settings.py +84 -0
- core/api/security.py +652 -0
- core/api/services/__init__.py +0 -0
- core/api/services/audit.py +58 -0
- core/api/services/auto_approval.py +82 -0
- core/api/services/brain/__init__.py +52 -0
- core/api/services/brain/baseline.py +230 -0
- core/api/services/brain/capabilities.py +75 -0
- core/api/services/brain/cascade_rollup.py +388 -0
- core/api/services/brain/compound_bridge.py +215 -0
- core/api/services/brain/cycle.py +1242 -0
- core/api/services/brain/cycle_snapshot.py +371 -0
- core/api/services/brain/digest_collector.py +147 -0
- core/api/services/brain/direction.py +421 -0
- core/api/services/brain/drift.py +356 -0
- core/api/services/brain/drift_router.py +409 -0
- core/api/services/brain/edge_metrics.py +79 -0
- core/api/services/brain/events_reader.py +222 -0
- core/api/services/brain/findings.py +1379 -0
- core/api/services/brain/findings_reader.py +1006 -0
- core/api/services/brain/jobs.py +733 -0
- core/api/services/brain/journal.py +206 -0
- core/api/services/brain/knowledge_forms.py +92 -0
- core/api/services/brain/llm/__init__.py +37 -0
- core/api/services/brain/llm/_runner.py +62 -0
- core/api/services/brain/llm/base.py +70 -0
- core/api/services/brain/llm/cache.py +99 -0
- core/api/services/brain/llm/constants.py +46 -0
- core/api/services/brain/llm/direction_alignment.py +289 -0
- core/api/services/brain/llm/factory.py +132 -0
- core/api/services/brain/llm/finding_reasoning.py +98 -0
- core/api/services/brain/llm/finding_summary.py +92 -0
- core/api/services/brain/llm/grounding.py +46 -0
- core/api/services/brain/llm/journal_polish.py +96 -0
- core/api/services/brain/llm/local_gateway.py +426 -0
- core/api/services/brain/llm/parsers.py +71 -0
- core/api/services/brain/llm/router_glue.py +422 -0
- core/api/services/brain/memory_ops.py +1677 -0
- core/api/services/brain/models.py +140 -0
- core/api/services/brain/owner_hint.py +211 -0
- core/api/services/brain/recap.py +307 -0
- core/api/services/brain/rules/__init__.py +65 -0
- core/api/services/brain/rules/_signals.py +205 -0
- core/api/services/brain/rules/dr1_activity_without_status.py +108 -0
- core/api/services/brain/rules/dr2_decision_without_adr.py +110 -0
- core/api/services/brain/rules/dr3_stale_open_loop.py +127 -0
- core/api/services/brain/rules/dr4_docs_governance_drift.py +79 -0
- core/api/services/brain/rules/dr5_playbook_changed.py +99 -0
- core/api/services/brain/rules/dr6_external_update_unpropagated.py +100 -0
- core/api/services/brain/rules/dr7_claimed_decision_gap.py +123 -0
- core/api/services/brain/rules/dr8_direction_misalignment.py +230 -0
- core/api/services/brain/runs_reader.py +485 -0
- core/api/services/brain/scope.py +79 -0
- core/api/services/brain/sources/__init__.py +46 -0
- core/api/services/brain/sources/base.py +86 -0
- core/api/services/brain/sources/git_kg.py +393 -0
- core/api/services/brain/sources/handoffs.py +157 -0
- core/api/services/brain/sources/ingestor.py +130 -0
- core/api/services/brain/sources/learnings.py +121 -0
- core/api/services/brain/sources/pir_tasks.py +245 -0
- core/api/services/brain/watermarks.py +147 -0
- core/api/services/brain/ws_emitter.py +170 -0
- core/api/services/cc_tasks_reader.py +76 -0
- core/api/services/ci_service.py +263 -0
- core/api/services/claude_metrics.py +796 -0
- core/api/services/codex_metrics.py +364 -0
- core/api/services/conversation_reader.py +102 -0
- core/api/services/cost_service.py +243 -0
- core/api/services/crypto.py +147 -0
- core/api/services/docs_governance/__init__.py +1 -0
- core/api/services/docs_governance/confidence.py +230 -0
- core/api/services/docs_governance/config.py +87 -0
- core/api/services/docs_governance/enrichment.py +65 -0
- core/api/services/docs_governance/frontmatter_validator.py +83 -0
- core/api/services/docs_governance/hard_gates.py +221 -0
- core/api/services/docs_governance/triage_orchestrator.py +98 -0
- core/api/services/embedding_internal.py +395 -0
- core/api/services/embedding_service.py +832 -0
- core/api/services/event_dispatcher.py +167 -0
- core/api/services/events.py +70 -0
- core/api/services/git_ops.py +621 -0
- core/api/services/graph_cosmo_service.py +440 -0
- core/api/services/graph_ranker.py +306 -0
- core/api/services/graph_service.py +1589 -0
- core/api/services/inbox.py +800 -0
- core/api/services/inbox_digest.py +221 -0
- core/api/services/inbox_digest_deep_research.py +80 -0
- core/api/services/inbox_digest_jobs.py +595 -0
- core/api/services/inbox_gmail_sync.py +167 -0
- core/api/services/inbox_llm_classifier.py +906 -0
- core/api/services/inbox_source_identity.py +116 -0
- core/api/services/inbox_sources.py +456 -0
- core/api/services/inbox_taxonomy.py +195 -0
- core/api/services/inbox_tldr.py +1079 -0
- core/api/services/inbox_triage.py +899 -0
- core/api/services/ingest/__init__.py +13 -0
- core/api/services/ingest/api_key_auth.py +136 -0
- core/api/services/ingest/auto_approve.py +120 -0
- core/api/services/ingest/classifier.py +138 -0
- core/api/services/ingest/confidence.py +173 -0
- core/api/services/ingest/dispatch.py +88 -0
- core/api/services/ingest/embedding_router.py +272 -0
- core/api/services/ingest/events.py +33 -0
- core/api/services/ingest/ignore_patterns.py +79 -0
- core/api/services/ingest/image_probe.py +218 -0
- core/api/services/ingest/ingress.py +263 -0
- core/api/services/ingest/insert_saga.py +793 -0
- core/api/services/ingest/llm/__init__.py +13 -0
- core/api/services/ingest/llm/anthropic_haiku.py +23 -0
- core/api/services/ingest/llm/base.py +59 -0
- core/api/services/ingest/llm/byok_provider.py +130 -0
- core/api/services/ingest/llm/classification_context.py +301 -0
- core/api/services/ingest/llm/config_store.py +246 -0
- core/api/services/ingest/llm/factory.py +24 -0
- core/api/services/ingest/llm/kg_enricher.py +306 -0
- core/api/services/ingest/llm/local_gateway.py +821 -0
- core/api/services/ingest/llm/local_vllm.py +23 -0
- core/api/services/ingest/llm/openai_nano.py +349 -0
- core/api/services/ingest/lock_advisory.py +57 -0
- core/api/services/ingest/parser_router.py +1756 -0
- core/api/services/ingest/parsers/__init__.py +1 -0
- core/api/services/ingest/parsers/docling_parser.py +142 -0
- core/api/services/ingest/parsers/docparse_gateway.py +178 -0
- core/api/services/ingest/parsers/docx_parser.py +127 -0
- core/api/services/ingest/parsers/folder_unpacker.py +85 -0
- core/api/services/ingest/parsers/gateway_aux.py +147 -0
- core/api/services/ingest/parsers/image_parser.py +251 -0
- core/api/services/ingest/parsers/internal_markdown.py +89 -0
- core/api/services/ingest/parsers/ocr_gateway.py +117 -0
- core/api/services/ingest/parsers/ocr_pdf_parser.py +112 -0
- core/api/services/ingest/parsers/pdf_types.py +13 -0
- core/api/services/ingest/parsers/transcript_parser.py +445 -0
- core/api/services/ingest/parsers/vision_gateway.py +186 -0
- core/api/services/ingest/parsers/xlsx_parser.py +91 -0
- core/api/services/ingest/parsers/zip_unpacker.py +126 -0
- core/api/services/ingest/preflight.py +393 -0
- core/api/services/ingest/retry_voyage.py +88 -0
- core/api/services/ingest/routing_policy.py +307 -0
- core/api/services/ingest/serializers/__init__.py +1 -0
- core/api/services/ingest/serializers/xlsx_to_markdown.py +80 -0
- core/api/services/ingest/skip_log.py +74 -0
- core/api/services/ingest/watcher.py +637 -0
- core/api/services/kg/__init__.py +0 -0
- core/api/services/kg/audit.py +49 -0
- core/api/services/kg/hybrid_search.py +691 -0
- core/api/services/kg/lens.py +339 -0
- core/api/services/kg/pr_impact.py +770 -0
- core/api/services/kg/queries.py +152 -0
- core/api/services/kg/ranking.py +89 -0
- core/api/services/kg/rrf.py +143 -0
- core/api/services/kg_watcher_control.py +161 -0
- core/api/services/local_llm/__init__.py +19 -0
- core/api/services/local_llm/async_client.py +385 -0
- core/api/services/local_llm/client.py +173 -0
- core/api/services/local_llm/url_validator.py +44 -0
- core/api/services/metrics_collector.py +646 -0
- core/api/services/metrics_providers.py +65 -0
- core/api/services/model_registry.py +266 -0
- core/api/services/model_router.py +137 -0
- core/api/services/n8n_client.py +77 -0
- core/api/services/newsletter_llm_gateway.py +66 -0
- core/api/services/notification_service.py +134 -0
- core/api/services/openai_responses.py +55 -0
- core/api/services/opencode_metrics.py +375 -0
- core/api/services/opencode_sessions.py +173 -0
- core/api/services/pii_redactor.py +138 -0
- core/api/services/pr_impact_pipeline/__init__.py +21 -0
- core/api/services/pr_impact_pipeline/differ.py +421 -0
- core/api/services/pr_impact_pipeline/dispatcher.py +415 -0
- core/api/services/pr_impact_pipeline/gc.py +93 -0
- core/api/services/pr_impact_pipeline/languages.py +192 -0
- core/api/services/pr_impact_pipeline/parser.py +178 -0
- core/api/services/pr_impact_pipeline/writer.py +394 -0
- core/api/services/pr_service.py +1393 -0
- core/api/services/project_paths.py +70 -0
- core/api/services/project_status_updates.py +265 -0
- core/api/services/providers.py +276 -0
- core/api/services/push_service.py +170 -0
- core/api/services/reminder_service.py +89 -0
- core/api/services/runas.py +41 -0
- core/api/services/salience_service.py +69 -0
- core/api/services/security_collector.py +281 -0
- core/api/services/session_catalog.py +385 -0
- core/api/services/session_metrics_service.py +301 -0
- core/api/services/session_ops.py +272 -0
- core/api/services/session_state.py +173 -0
- core/api/services/share_links.py +222 -0
- core/api/services/task_transitions.py +146 -0
- core/api/services/terminal_metrics.py +462 -0
- core/api/services/terminal_metrics_dump.py +203 -0
- core/api/services/tmux.py +1205 -0
- core/api/services/webhook_service.py +422 -0
- core/api/services/workspace_sync.py +164 -0
- core/api/templates/__init__.py +1 -0
- core/api/templates/markdown_share.py +164 -0
- core/api/terminal.py +1031 -0
- core/api/tests/__init__.py +0 -0
- core/api/tests/test_agent_facing_auth_dependencies.py +132 -0
- core/api/tests/test_audit_permissions.py +133 -0
- core/api/tests/test_backfill_session_conversations.py +90 -0
- core/api/tests/test_backfill_working_seconds_msg.py +129 -0
- core/api/tests/test_claude_metrics.py +326 -0
- core/api/tests/test_codex_metrics.py +189 -0
- core/api/tests/test_finder_paths.py +74 -0
- core/api/tests/test_git_ops_merge.py +155 -0
- core/api/tests/test_learnings_check_search.py +81 -0
- core/api/tests/test_metrics_providers.py +133 -0
- core/api/tests/test_migration_087.py +164 -0
- core/api/tests/test_migration_088.py +94 -0
- core/api/tests/test_migration_089.py +116 -0
- core/api/tests/test_openai_responses.py +24 -0
- core/api/tests/test_opencode_metrics.py +740 -0
- core/api/tests/test_opencode_sessions.py +321 -0
- core/api/tests/test_pr_workflow_e2e.py +457 -0
- core/api/tests/test_projects_handoffs.py +31 -0
- core/api/tests/test_providers.py +138 -0
- core/api/tests/test_safety_bridge.py +347 -0
- core/api/tests/test_session_catalog.py +142 -0
- core/api/tests/test_session_conversations.py +512 -0
- core/api/tests/test_session_metrics_service.py +270 -0
- core/api/tests/test_session_resume_paths.py +548 -0
- core/api/tests/test_session_theme_mode_migration.py +56 -0
- core/api/tests/test_sessions_rbac.py +131 -0
- core/api/tests/test_share_edit.py +398 -0
- core/api/tests/test_share_repo.py +200 -0
- core/api/tests/test_terminal_session_manager.py +98 -0
- core/api/tests/test_terminal_upload.py +34 -0
- core/api/tests/test_tmux.py +272 -0
- core/api/tests/test_workspace_sync.py +186 -0
- core/api/tests/test_ws_ticket_in_memory.py +73 -0
- core/api/use_cases/__init__.py +11 -0
- core/api/use_cases/_context.py +89 -0
- core/api/use_cases/_errors.py +62 -0
- core/api/use_cases/_roles.py +16 -0
- core/api/use_cases/audit.py +171 -0
- core/api/use_cases/brain.py +1232 -0
- core/api/use_cases/costs.py +249 -0
- core/api/use_cases/graph.py +1153 -0
- core/api/use_cases/handoffs.py +506 -0
- core/api/use_cases/ingest_triage.py +1229 -0
- core/api/use_cases/learnings.py +538 -0
- core/api/use_cases/projects.py +705 -0
- core/api/use_cases/pull_requests.py +415 -0
- core/api/use_cases/search.py +926 -0
- core/api/use_cases/tasks.py +1495 -0
- core/api/visibility.py +141 -0
- core/cli/__init__.py +5 -0
- core/cli/_index_source.py +632 -0
- core/cli/_runtime_ctx.py +160 -0
- core/cli/_transmute.py +241 -0
- core/cli/marvis_doctor.py +704 -0
- core/cli/marvis_feedback.py +396 -0
- core/cli/marvis_governance.py +315 -0
- core/cli/marvis_hooks.py +515 -0
- core/cli/marvis_init.py +757 -0
- core/cli/marvis_mcp.py +401 -0
- core/cli/marvis_runtime.py +855 -0
- core/cli/marvis_telemetry.py +228 -0
- core/scripts/_drift_check.py +716 -0
- core/scripts/_frontmatter.py +66 -0
- core/scripts/_graph_writer.py +189 -0
- core/scripts/ast_parser.py +1553 -0
- core/scripts/install_hooks/__init__.py +1 -0
- core/scripts/install_hooks/_config.sh +109 -0
- core/scripts/install_hooks/block-dangerous-bash.sh +23 -0
- core/scripts/install_hooks/block-db-direct-write.sh +23 -0
- core/scripts/install_hooks/block-push-no-task.sh +23 -0
- core/scripts/install_hooks/block-staging-to-prod.sh +23 -0
- core/scripts/install_hooks/block-subtree-push.sh +23 -0
- core/scripts/install_hooks/config.json +53 -0
- core/scripts/install_hooks/enforce-no-merge-main.sh +23 -0
- core/scripts/install_hooks/enforce-worktree.sh +23 -0
- core/scripts/install_hooks/quality-gate.sh +170 -0
- core/scripts/install_hooks/safety_bridge.py +968 -0
- core/scripts/install_hooks/secret-scan.sh +23 -0
- core/scripts/migrate_spike_node_ids.py +122 -0
- core/scripts/populate_artifacts.py +2198 -0
- core/scripts/populate_cross_project.py +2457 -0
- core/scripts/populate_inbox_nodes.py +357 -0
- core/scripts/populate_pr_impact.py +267 -0
- core/scripts/populate_project_nodes.py +603 -0
- core/scripts/populate_touch_counter.py +337 -0
- core/scripts/reparse_failed.py +57 -0
- core/scripts/safety_bridge.py +968 -0
- core/telemetry/__init__.py +9 -0
- core/telemetry/client.py +405 -0
- core/telemetry/schema.py +122 -0
- core/wizard/__init__.py +65 -0
- core/wizard/byok_vault.py +147 -0
- core/wizard/defaults.py +58 -0
- core/wizard/state.py +117 -0
- core/wizard/steps.py +70 -0
- core/wizard/validation.py +136 -0
- marvisx_cli-0.1.0.dist-info/METADATA +201 -0
- marvisx_cli-0.1.0.dist-info/RECORD +587 -0
- marvisx_cli-0.1.0.dist-info/WHEEL +5 -0
- marvisx_cli-0.1.0.dist-info/entry_points.txt +3 -0
- marvisx_cli-0.1.0.dist-info/licenses/LICENSE +98 -0
- marvisx_cli-0.1.0.dist-info/top_level.txt +3 -0
- migrations/001_initial.sql +33 -0
- migrations/002_tasks.sql +30 -0
- migrations/003_session_management.sql +7 -0
- migrations/004_projects_comments.sql +65 -0
- migrations/005_session_intelligence.sql +15 -0
- migrations/006_settings.sql +12 -0
- migrations/007_task_scoring.sql +12 -0
- migrations/008_cost_tracking.sql +31 -0
- migrations/009_session_card_metrics.sql +3 -0
- migrations/010_monitoring.sql +55 -0
- migrations/012_agent_api.sql +21 -0
- migrations/013_session_complete.sql +8 -0
- migrations/015_pull_requests.sql +43 -0
- migrations/015_pull_requests_down.sql +5 -0
- migrations/016_users_raci.sql +116 -0
- migrations/017_task_cost_entries.sql +87 -0
- migrations/018_agents.sql +73 -0
- migrations/018_agents_down.sql +13 -0
- migrations/019_review_feedback.sql +18 -0
- migrations/020_pr_commit_sha.sql +4 -0
- migrations/021_webhook_events.sql +18 -0
- migrations/022_devx_agent_managed.sql +11 -0
- migrations/022_devx_agent_managed_down.sql +6 -0
- migrations/023_devx_p1_gate.sql +7 -0
- migrations/023_devx_p1_gate_down.sql +3 -0
- migrations/024_chat_messages.sql +16 -0
- migrations/024_pr_conversation_id.sql +8 -0
- migrations/024_task_indexes.sql +21 -0
- migrations/024_task_indexes_down.sql +7 -0
- migrations/025_audit_log.sql +17 -0
- migrations/026_agent_tokens.sql +20 -0
- migrations/027_teams_auth_phase_b.sql +35 -0
- migrations/028_learnings.sql +23 -0
- migrations/029_team_roles.sql +14 -0
- migrations/030_finder_pins.sql +10 -0
- migrations/031_pr_deploy_status.sql +9 -0
- migrations/032_task_reminders.sql +7 -0
- migrations/033_events_retry_count.sql +6 -0
- migrations/033_session_owner.sql +9 -0
- migrations/034_notifications.sql +38 -0
- migrations/035_shared_links.sql +15 -0
- migrations/036_session_index_upgrade.sql +29 -0
- migrations/037_pr_approval.sql +15 -0
- migrations/038_pr_submitted_by.sql +6 -0
- migrations/039_push_subscriptions.sql +17 -0
- migrations/040_semantic_search.sql +16 -0
- migrations/041_workspaces.sql +63 -0
- migrations/042_oidc_providers.sql +24 -0
- migrations/043_ci_checks.sql +31 -0
- migrations/044_agent_metrics.sql +30 -0
- migrations/045_documents_doc_type.sql +5 -0
- migrations/046_salience.sql +13 -0
- migrations/047_seed_missing_agents.sql +6 -0
- migrations/048_fix_agent_paths_roles.sql +5 -0
- migrations/049_agent_role_and_learnings_schema.sql +3 -0
- migrations/050_session_provider.sql +2 -0
- migrations/051_session_launch_profile.sql +4 -0
- migrations/052_session_theme_mode.sql +2 -0
- migrations/052_task_kind.sql +4 -0
- migrations/053_inbox_items.sql +31 -0
- migrations/054_inbox_triage_contract.sql +30 -0
- migrations/055_inbox_topic_treatment.sql +12 -0
- migrations/056_inbox_treatment_read_save.sql +57 -0
- migrations/057_session_theme_mode_backfill.sql +4 -0
- migrations/058_inbox_item_status_lifecycle.sql +13 -0
- migrations/059_inbox_tldr_and_source_scores.sql +18 -0
- migrations/060_newsletter.sql +16 -0
- migrations/061_inbox_redesign.sql +69 -0
- migrations/062_fix_inbox_sources_backfill.sql +37 -0
- migrations/063_task_completion_mode.sql +23 -0
- migrations/064_judge_mode_setting.sql +4 -0
- migrations/065_knowledge_graph_spike.sql +40 -0
- migrations/066_digest_ranking_inputs.sql +10 -0
- migrations/066_kg_artifact_nodes.sql +129 -0
- migrations/067_inbox_digest_selections.sql +28 -0
- migrations/067_kg_temporal.sql +53 -0
- migrations/068_inbox_digest_app_settings.sql +9 -0
- migrations/068_kg_touch_counter.sql +52 -0
- migrations/069_kg_doc_types.sql +117 -0
- migrations/070_digest_ranking_inputs_recovery.sql +3 -0
- migrations/071_inbox_digest_selections_recovery.sql +3 -0
- migrations/072_inbox_digest_app_settings_recovery.sql +3 -0
- migrations/073_kg_cross_project.sql +216 -0
- migrations/073_kg_cross_project_down.sql +77 -0
- migrations/074_kg_infra_types.sql +208 -0
- migrations/074_kg_infra_types_down.sql +80 -0
- migrations/075_kg_file_state_recovery.sql +35 -0
- migrations/075_kg_file_state_recovery_down.sql +5 -0
- migrations/076_kg_watcher_state.sql +33 -0
- migrations/076_kg_watcher_state_down.sql +3 -0
- migrations/077_kg_doc_types_extend.sql +226 -0
- migrations/077_kg_doc_types_extend_down.sql +80 -0
- migrations/078_kg_fts5.sql +102 -0
- migrations/078_kg_fts5_down.sql +14 -0
- migrations/079_kg_missing_indexes.sql +31 -0
- migrations/079_kg_missing_indexes_down.sql +10 -0
- migrations/080_kg_fts5_extended.sql +232 -0
- migrations/080_kg_fts5_extended_down.sql +25 -0
- migrations/081_kg_lens_indexes.sql +9 -0
- migrations/081_kg_lens_indexes_down.sql +3 -0
- migrations/082_kg_pins.sql +26 -0
- migrations/082_kg_pins_down.sql +14 -0
- migrations/083_kg_graph_nodes_degree.sql +20 -0
- migrations/083_kg_graph_nodes_degree_down.sql +15 -0
- migrations/084_drop_legacy_scheduler_tables.sql +58 -0
- migrations/084_drop_legacy_scheduler_tables_down.sql +112 -0
- migrations/085_kg_edge_resolves_to.sql +142 -0
- migrations/085_kg_edge_resolves_to_down.sql +66 -0
- migrations/086_project_status_updates_feed.sql +20 -0
- migrations/086_project_status_updates_feed_down.sql +36 -0
- migrations/087_session_metrics_dual.sql +50 -0
- migrations/087_session_metrics_dual_down.sql +21 -0
- migrations/088_rename_context_pct_legacy.sql +23 -0
- migrations/088_rename_context_pct_legacy_down.sql +8 -0
- migrations/089_session_metrics_equivalent_cost.sql +26 -0
- migrations/089_session_metrics_equivalent_cost_down.sql +11 -0
- migrations/090_kg_inbox_node_type.sql +26 -0
- migrations/090_kg_inbox_node_type_down.sql +20 -0
- migrations/091_kg_inbox_node_type_check.sql +265 -0
- migrations/091_kg_inbox_node_type_check_down.sql +129 -0
- migrations/092_sessions_activity_state_ts.sql +29 -0
- migrations/092_sessions_activity_state_ts_down.sql +14 -0
- migrations/093_sessions_activity_state_column.sql +29 -0
- migrations/093_sessions_activity_state_column_down.sql +10 -0
- migrations/094_ingest_pending.sql +55 -0
- migrations/094_ingest_pending_down.sql +15 -0
- migrations/095_kg_intent_first.sql +77 -0
- migrations/095_kg_intent_first_down.sql +25 -0
- migrations/096_kg_xlsx_artifact_prefix.sql +17 -0
- migrations/096_kg_xlsx_artifact_prefix_down.sql +11 -0
- migrations/097_ingest_change_history.sql +37 -0
- migrations/097_ingest_change_history_down.sql +13 -0
- migrations/098_kg_node_type_business.sql +254 -0
- migrations/098_kg_node_type_business_down.sql +195 -0
- migrations/099_kg_edges_restore_weight.sql +58 -0
- migrations/099_kg_edges_restore_weight_down.sql +12 -0
- migrations/100_kg_enriched_at.sql +25 -0
- migrations/100_kg_enriched_at_down.sql +12 -0
- migrations/101_local_llm_shadow_comparisons.sql +66 -0
- migrations/101_local_llm_shadow_comparisons_down.sql +15 -0
- migrations/102_promote_llm_costs.sql +69 -0
- migrations/102_promote_llm_costs_down.sql +19 -0
- migrations/103_ingest_skipped_log.sql +46 -0
- migrations/103_ingest_skipped_log_down.sql +15 -0
- migrations/120_docs_governance.sql +50 -0
- migrations/120_docs_governance_down.sql +11 -0
- migrations/121_notification_event_fk_cleanup.sql +21 -0
- migrations/121_notification_event_fk_cleanup_down.sql +10 -0
- migrations/122_docs_drift_history.sql +34 -0
- migrations/122_docs_drift_history_down.sql +15 -0
- migrations/123_ingest_parser_waiting_status.sql +69 -0
- migrations/123_ingest_parser_waiting_status_down.sql +69 -0
- migrations/124_heypocket_recordings.sql +63 -0
- migrations/124_heypocket_recordings_down.sql +13 -0
- migrations/125_kg_node_type_record.sql +219 -0
- migrations/125_kg_node_type_record_down.sql +205 -0
- migrations/126_ingest_terminal_upload_source_kind.sql +69 -0
- migrations/126_ingest_terminal_upload_source_kind_down.sql +69 -0
- migrations/127_brain_v1_substrate.sql +200 -0
- migrations/127_brain_v1_substrate_down.sql +32 -0
- migrations/128_brain_drift_signals.sql +157 -0
- migrations/128_brain_drift_signals_down.sql +23 -0
- migrations/129_brain_memory_operations.sql +232 -0
- migrations/129_brain_memory_operations_down.sql +27 -0
- migrations/130_brain_findings.sql +258 -0
- migrations/130_brain_findings_down.sql +29 -0
- migrations/132_kg_pr_modifies.sql +242 -0
- migrations/132_kg_pr_modifies_down.sql +99 -0
- migrations/133_brain_v1_2_direction_schema.sql +476 -0
- migrations/133_brain_v1_2_direction_schema_down.sql +273 -0
- migrations/134_brain_journal_narrative_polished.sql +8 -0
- migrations/134_brain_journal_narrative_polished_down.sql +6 -0
- migrations/135_kg_edges_provider.sql +21 -0
- migrations/136_documents_fts.sql +56 -0
- migrations/137_promote_llm_costs.sql +59 -0
- migrations/137_promote_llm_costs_down.sql +19 -0
- migrations/138_ingest_api_keys.sql +39 -0
- migrations/138_ingest_api_keys_down.sql +8 -0
- migrations/139_ingest_pending_ingress.sql +91 -0
- migrations/139_ingest_pending_ingress_down.sql +73 -0
- migrations/140_ingest_idempotency_quota.sql +45 -0
- migrations/140_ingest_idempotency_quota_down.sql +9 -0
- migrations/141_ingest_pending_metadata.sql +16 -0
- migrations/141_ingest_pending_metadata_down.sql +7 -0
- migrations/142_llm_function_config.sql +36 -0
- migrations/142_llm_function_config_down.sql +8 -0
- migrations/143_kg_code_embeddings.sql +25 -0
- migrations/143_kg_code_embeddings_down.sql +5 -0
- migrations/__init__.py +4 -0
- projects/_template/project.yaml +46 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
# v1.0.0 - 2026-05-27 - S1 F1.7: pull_requests use_cases extracted from router (merge human-gate)
|
|
2
|
+
"""Pull-requests use_cases — pure domain logic, transport-agnostic (no ``fastapi``).
|
|
3
|
+
|
|
4
|
+
Sibling of :mod:`core.api.use_cases.learnings` (the S1 "collapse runtime"
|
|
5
|
+
TEMPLATE). One pure async function per operation, signature
|
|
6
|
+
``(ctx: CallerContext, db, *typed_args) -> <DTO/dict>``. The HTTP router becomes a
|
|
7
|
+
thin adapter that resolves identity into a :class:`CallerContext`, calls these
|
|
8
|
+
functions, and maps :class:`ServiceError` -> ``HTTPException`` via
|
|
9
|
+
``routers/_adapter.to_http``. The Python MCP surface (later) calls the SAME
|
|
10
|
+
functions with ``CallerContext.local_single_user()``. One implementation, no fork.
|
|
11
|
+
|
|
12
|
+
How the template decisions land on the PR domain:
|
|
13
|
+
|
|
14
|
+
MERGE HUMAN-GATE — stays a transport-layer ``Depends``, NOT duplicated here.
|
|
15
|
+
The legacy ``POST /{task_id}/merge`` (and ``/revert``) used
|
|
16
|
+
``Depends(require_role(..., human_only=True))``. ``human_only=True`` swaps the
|
|
17
|
+
auth dependency to ``get_current_user`` (cookie-only), so a Bearer-only agent
|
|
18
|
+
is rejected with ``401 Not authenticated`` BEFORE any handler/``ctx`` exists
|
|
19
|
+
(pinned by the merge-gate regression test ``test_br03_merge_pr_blocked_without_cookie``,
|
|
20
|
+
which asserts 401/403). A use_case receiving a ``ctx`` cannot reproduce that
|
|
21
|
+
401 — authentication failure happens at the dependency, upstream of the domain.
|
|
22
|
+
So the adapter KEEPS ``Depends(require_role(..., human_only=True))`` and this
|
|
23
|
+
module does NOT add an ``is_human_session`` check on merge/revert: it would be
|
|
24
|
+
dead on both surfaces (HTTP already blocked agents; the MCP/local surface is
|
|
25
|
+
always ``is_human_session=True`` operator). Each write use_case still calls
|
|
26
|
+
:func:`require_role_ctx` so the ROLE-level gate is enforced on the MCP surface
|
|
27
|
+
(parity with the tasks template, which keeps ``require_role_ctx`` despite the
|
|
28
|
+
router's ``Depends(require_role(...))``).
|
|
29
|
+
|
|
30
|
+
DECISION 1 — Visibility on ``get_merge_conflicts``. The legacy endpoint called
|
|
31
|
+
``check_project_access(project, user, db)`` (raises 404 if the project is not
|
|
32
|
+
visible — does not reveal existence). ``UserInfo.teams`` is NOT carried by
|
|
33
|
+
``CallerContext``, so the ADAPTER resolves ``visible_projects`` and passes it
|
|
34
|
+
in; this use_case enforces it by raising :class:`NotFoundError` (same 404,
|
|
35
|
+
same ``"Not found"`` shape) when the project is outside the visible set.
|
|
36
|
+
``visible_projects=None`` means "no restriction" (admin/agent or MCP/local).
|
|
37
|
+
|
|
38
|
+
DECISION 2 — ``deep`` KG enrichment on ``get_pull_request`` is a per-surface
|
|
39
|
+
adapter concern (rate-limit + access log + ``build_kg_context_for_pr``). It
|
|
40
|
+
also depends on ``core.api.services.kg.audit`` which imports ``fastapi`` at
|
|
41
|
+
module top, so it MUST NOT touch this module. ``get_pull_request`` returns the
|
|
42
|
+
PR status dict as-is; the adapter attaches ``kg_context`` when ``deep``.
|
|
43
|
+
|
|
44
|
+
SERVICE IMPORTS ARE FUNCTION-LOCAL (the search.py pattern). ``pr_service`` imports
|
|
45
|
+
``fastapi.HTTPException`` (a Fase-2 conversion target, OUT OF SCOPE here), so
|
|
46
|
+
importing it at module top would pull ``fastapi`` into ``use_cases`` and break
|
|
47
|
+
the import-linter ``use_cases-no-fastapi`` contract. Every use_case imports
|
|
48
|
+
``pr_service`` (and ``services.audit.log_audit``) INSIDE the function body.
|
|
49
|
+
``HTTPException``s raised inside ``pr_service`` (the title/migration/push paths)
|
|
50
|
+
propagate natively over HTTP for now — correct behavior; their conversion to
|
|
51
|
+
``ServiceError`` is Fase 2 and explicitly not done here.
|
|
52
|
+
|
|
53
|
+
ERROR TRANSLATION. The errors the ROUTER ITSELF raised (catching ``pr_service``'s
|
|
54
|
+
``ValueError`` / ``PermissionError`` / ``GitOpsError`` / ``MergeConflictError``)
|
|
55
|
+
become domain :class:`ServiceError` subclasses here with the SAME status:
|
|
56
|
+
* ``ValueError`` -> ``ConflictError`` (409) on ``create_branch`` /
|
|
57
|
+
``NotFoundError`` (404) on ``get_pull_request`` / ``ValidationError`` (422)
|
|
58
|
+
elsewhere — matching each endpoint's original status verbatim.
|
|
59
|
+
* ``PermissionError`` -> ``AuthorizationError`` (403) on approve/request-changes.
|
|
60
|
+
* ``MergeConflictError`` -> ``MergeConflictError`` is re-raised UNCHANGED so
|
|
61
|
+
the adapter can build the exact legacy 409 dict body (``message`` +
|
|
62
|
+
``conflicting_files``) — ``to_http`` only emits ``{code,message}`` and would
|
|
63
|
+
drop ``conflicting_files``.
|
|
64
|
+
* plain ``GitOpsError`` -> re-raised UNCHANGED so the adapter maps it to the
|
|
65
|
+
legacy ``HTTPException(500, str(exc))`` (pinned by
|
|
66
|
+
``tests/test_db_contention_task_flows.py::test_merge_push_failure_*`` which
|
|
67
|
+
asserts the raw message text in the 500 body). ``to_http``'s structured
|
|
68
|
+
dict would break that substring assertion.
|
|
69
|
+
``MergeConflictError`` / ``GitOpsError`` come from ``services.git_ops`` which is
|
|
70
|
+
fastapi-free, so they are imported at module top (safe).
|
|
71
|
+
|
|
72
|
+
``MergeConflictResponse`` (response DTO) lives in ``core.api.models`` and is NOT
|
|
73
|
+
moved (like costs/tasks). The router keeps the REQUEST models.
|
|
74
|
+
"""
|
|
75
|
+
from __future__ import annotations
|
|
76
|
+
|
|
77
|
+
import logging
|
|
78
|
+
|
|
79
|
+
import aiosqlite
|
|
80
|
+
|
|
81
|
+
from core.api.services.git_ops import GitOpsError, MergeConflictError
|
|
82
|
+
from core.api.use_cases._context import CallerContext, require_role_ctx
|
|
83
|
+
from core.api.use_cases._errors import (
|
|
84
|
+
ConflictError,
|
|
85
|
+
NotFoundError,
|
|
86
|
+
ServiceError,
|
|
87
|
+
ValidationError,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
logger = logging.getLogger(__name__)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
# Use cases — reads
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async def get_merge_conflicts(
|
|
99
|
+
ctx: CallerContext,
|
|
100
|
+
db: aiosqlite.Connection,
|
|
101
|
+
*,
|
|
102
|
+
project: str,
|
|
103
|
+
visible_projects: set[str] | None = None,
|
|
104
|
+
) -> list[dict]:
|
|
105
|
+
"""Detect migration-number conflicts across open PRs for a project.
|
|
106
|
+
|
|
107
|
+
Any authenticated caller. Visibility (DECISION 1): the adapter resolves
|
|
108
|
+
``visible_projects``; this use_case raises :class:`NotFoundError` (404, same
|
|
109
|
+
``"Not found"`` shape as the legacy ``check_project_access``) when ``project``
|
|
110
|
+
is outside the visible set. ``None`` is unrestricted.
|
|
111
|
+
|
|
112
|
+
Raises :class:`ValidationError` (422) on a bad project arg and re-raises
|
|
113
|
+
:class:`GitOpsError` (-> 500 in the adapter) — matching the legacy router.
|
|
114
|
+
"""
|
|
115
|
+
if visible_projects is not None and project not in visible_projects:
|
|
116
|
+
raise NotFoundError(code="project_not_found", message="Not found")
|
|
117
|
+
|
|
118
|
+
from core.api.services import pr_service
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
return await pr_service.get_merge_conflicts(project, db)
|
|
122
|
+
except ValueError as exc:
|
|
123
|
+
raise ValidationError(code="invalid_merge_conflicts_request", message=str(exc))
|
|
124
|
+
# GitOpsError propagates; the adapter maps it to the legacy 500.
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def get_pull_request(
|
|
128
|
+
ctx: CallerContext,
|
|
129
|
+
db: aiosqlite.Connection,
|
|
130
|
+
*,
|
|
131
|
+
task_id: str,
|
|
132
|
+
) -> dict:
|
|
133
|
+
"""Get PR status and diff for a task (any authenticated caller).
|
|
134
|
+
|
|
135
|
+
Returns the ``pr_service.get_pr_status`` dict as-is. The ``deep`` KG context
|
|
136
|
+
is a per-surface adapter concern (DECISION 2) — the adapter attaches it.
|
|
137
|
+
Raises :class:`NotFoundError` (404) when no PR exists for the task.
|
|
138
|
+
"""
|
|
139
|
+
from core.api.services import pr_service
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
return await pr_service.get_pr_status(task_id, db)
|
|
143
|
+
except ValueError as exc:
|
|
144
|
+
raise NotFoundError(code="pr_not_found", message=str(exc))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
# Use cases — writes (branch/PR lifecycle)
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
async def create_branch(
|
|
153
|
+
ctx: CallerContext,
|
|
154
|
+
db: aiosqlite.Connection,
|
|
155
|
+
*,
|
|
156
|
+
task_id: str,
|
|
157
|
+
) -> dict:
|
|
158
|
+
"""Create git worktree and branch for a task (operator+). Idempotent.
|
|
159
|
+
|
|
160
|
+
Raises :class:`ConflictError` (409) on a ``ValueError`` (matching the legacy
|
|
161
|
+
409) and re-raises :class:`GitOpsError` (-> 500 in the adapter).
|
|
162
|
+
"""
|
|
163
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
164
|
+
|
|
165
|
+
from core.api.services import pr_service
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
return await pr_service.start_branch_short_write(task_id, db)
|
|
169
|
+
except ValueError as exc:
|
|
170
|
+
raise ConflictError(code="branch_conflict", message=str(exc))
|
|
171
|
+
# GitOpsError propagates; the adapter maps it to the legacy 500.
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
async def register_branch(
|
|
175
|
+
ctx: CallerContext,
|
|
176
|
+
db: aiosqlite.Connection,
|
|
177
|
+
*,
|
|
178
|
+
task_id: str,
|
|
179
|
+
branch_name: str,
|
|
180
|
+
worktree_path: str | None = None,
|
|
181
|
+
) -> dict:
|
|
182
|
+
"""Register an externally-created branch as a draft PR record (operator+).
|
|
183
|
+
|
|
184
|
+
Idempotent: returns the existing active PR if one already exists. Raises
|
|
185
|
+
:class:`ValidationError` (422) on a ``ValueError`` (matching the legacy 422).
|
|
186
|
+
"""
|
|
187
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
188
|
+
|
|
189
|
+
from core.api.services import pr_service
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
return await pr_service.register_branch(
|
|
193
|
+
task_id, branch_name, db, worktree_path=worktree_path
|
|
194
|
+
)
|
|
195
|
+
except ValueError as exc:
|
|
196
|
+
raise ValidationError(code="register_branch_failed", message=str(exc))
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
async def submit_pull_request(
|
|
200
|
+
ctx: CallerContext,
|
|
201
|
+
db: aiosqlite.Connection,
|
|
202
|
+
*,
|
|
203
|
+
task_id: str,
|
|
204
|
+
title: str,
|
|
205
|
+
body: str = "",
|
|
206
|
+
) -> dict:
|
|
207
|
+
"""Submit branch for review — moves the PR from draft to open (operator+).
|
|
208
|
+
|
|
209
|
+
``submitted_by`` is ``ctx.user_id`` (the original router passed
|
|
210
|
+
``user.user_id``). Raises :class:`ValidationError` (422) on a ``ValueError``
|
|
211
|
+
and re-raises :class:`GitOpsError` (-> 500 in the adapter).
|
|
212
|
+
"""
|
|
213
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
214
|
+
|
|
215
|
+
from core.api.services import pr_service
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
return await pr_service.submit_pr(
|
|
219
|
+
task_id, title, body, db, submitted_by=ctx.user_id
|
|
220
|
+
)
|
|
221
|
+
except ValueError as exc:
|
|
222
|
+
raise ValidationError(code="submit_pr_failed", message=str(exc))
|
|
223
|
+
# GitOpsError propagates; the adapter maps it to the legacy 500.
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
async def merge_pull_request(
|
|
227
|
+
ctx: CallerContext,
|
|
228
|
+
db: aiosqlite.Connection,
|
|
229
|
+
*,
|
|
230
|
+
task_id: str,
|
|
231
|
+
) -> dict:
|
|
232
|
+
"""Merge a PR (operator+). The HUMAN-ONLY gate is enforced at the HTTP
|
|
233
|
+
``Depends(require_role(..., human_only=True))`` (see module docstring) — it is
|
|
234
|
+
NOT re-checked here, by design.
|
|
235
|
+
|
|
236
|
+
Writes a ``pr.merge`` audit entry (``merger_id=ctx.user_id``) on success.
|
|
237
|
+
Raises :class:`ValidationError` (422) on a ``ValueError`` and re-raises both
|
|
238
|
+
:class:`MergeConflictError` (-> legacy 409 dict body) and plain
|
|
239
|
+
:class:`GitOpsError` (-> legacy 500 plain body) UNCHANGED so the adapter can
|
|
240
|
+
preserve those exact legacy bodies.
|
|
241
|
+
"""
|
|
242
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
243
|
+
|
|
244
|
+
from core.api.services import pr_service
|
|
245
|
+
from core.api.services.audit import log_audit
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
result = await pr_service.merge_pr(task_id, db, merger_id=ctx.user_id)
|
|
249
|
+
except ValueError as exc:
|
|
250
|
+
raise ValidationError(code="merge_failed", message=str(exc))
|
|
251
|
+
# MergeConflictError (subclass of GitOpsError) and plain GitOpsError propagate;
|
|
252
|
+
# the adapter maps them to the exact legacy 409 dict / 500 plain-string bodies.
|
|
253
|
+
|
|
254
|
+
await log_audit(
|
|
255
|
+
db,
|
|
256
|
+
action="pr.merge",
|
|
257
|
+
user=ctx.username,
|
|
258
|
+
resource_type="pull_request",
|
|
259
|
+
resource_id=task_id,
|
|
260
|
+
details={"task_id": task_id},
|
|
261
|
+
)
|
|
262
|
+
return result
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
async def approve_pull_request(
|
|
266
|
+
ctx: CallerContext,
|
|
267
|
+
db: aiosqlite.Connection,
|
|
268
|
+
*,
|
|
269
|
+
task_id: str,
|
|
270
|
+
reviewer,
|
|
271
|
+
) -> dict:
|
|
272
|
+
"""Approve a PR (operator+, team_admin of the project or admin+). Four-eyes:
|
|
273
|
+
cannot approve your own PR.
|
|
274
|
+
|
|
275
|
+
``pr_service.approve_pr`` needs the full ``UserInfo`` (``user_id`` + team
|
|
276
|
+
lookups), which is richer than ``CallerContext``, so the adapter passes the
|
|
277
|
+
resolved ``reviewer`` (the ``UserInfo``) through. Raises
|
|
278
|
+
:class:`ValidationError` (422) on a ``ValueError`` and :class:`AuthorizationError`
|
|
279
|
+
(403) on a ``PermissionError`` — matching the legacy router.
|
|
280
|
+
"""
|
|
281
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
282
|
+
|
|
283
|
+
from core.api.services import pr_service
|
|
284
|
+
from core.api.use_cases._errors import AuthorizationError
|
|
285
|
+
|
|
286
|
+
try:
|
|
287
|
+
return await pr_service.approve_pr(task_id, reviewer, db)
|
|
288
|
+
except ValueError as exc:
|
|
289
|
+
raise ValidationError(code="approve_pr_failed", message=str(exc))
|
|
290
|
+
except PermissionError as exc:
|
|
291
|
+
raise AuthorizationError(code="approve_pr_forbidden", message=str(exc))
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
async def request_pull_request_changes(
|
|
295
|
+
ctx: CallerContext,
|
|
296
|
+
db: aiosqlite.Connection,
|
|
297
|
+
*,
|
|
298
|
+
task_id: str,
|
|
299
|
+
reviewer,
|
|
300
|
+
comment: str,
|
|
301
|
+
) -> dict:
|
|
302
|
+
"""Request changes on a PR (operator+). Revokes approval, sends the task back
|
|
303
|
+
to in_progress.
|
|
304
|
+
|
|
305
|
+
Like :func:`approve_pull_request`, the adapter passes the full ``UserInfo``
|
|
306
|
+
``reviewer``. Raises :class:`ValidationError` (422) on a ``ValueError`` and
|
|
307
|
+
:class:`AuthorizationError` (403) on a ``PermissionError``.
|
|
308
|
+
"""
|
|
309
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
310
|
+
|
|
311
|
+
from core.api.services import pr_service
|
|
312
|
+
from core.api.use_cases._errors import AuthorizationError
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
return await pr_service.request_changes_pr(task_id, reviewer, comment, db)
|
|
316
|
+
except ValueError as exc:
|
|
317
|
+
raise ValidationError(code="request_changes_failed", message=str(exc))
|
|
318
|
+
except PermissionError as exc:
|
|
319
|
+
raise AuthorizationError(code="request_changes_forbidden", message=str(exc))
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
async def close_pull_request(
|
|
323
|
+
ctx: CallerContext,
|
|
324
|
+
db: aiosqlite.Connection,
|
|
325
|
+
*,
|
|
326
|
+
task_id: str,
|
|
327
|
+
reason: str = "",
|
|
328
|
+
) -> dict:
|
|
329
|
+
"""Close a PR without merge — the task returns to in_progress (operator+).
|
|
330
|
+
|
|
331
|
+
Raises :class:`ValidationError` (422) on a ``ValueError`` (matching legacy).
|
|
332
|
+
"""
|
|
333
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
334
|
+
|
|
335
|
+
from core.api.services import pr_service
|
|
336
|
+
|
|
337
|
+
try:
|
|
338
|
+
return await pr_service.close_pr(task_id, reason, db)
|
|
339
|
+
except ValueError as exc:
|
|
340
|
+
raise ValidationError(code="close_pr_failed", message=str(exc))
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
async def update_pull_request(
|
|
344
|
+
ctx: CallerContext,
|
|
345
|
+
db: aiosqlite.Connection,
|
|
346
|
+
*,
|
|
347
|
+
task_id: str,
|
|
348
|
+
title: str | None = None,
|
|
349
|
+
body: str | None = None,
|
|
350
|
+
) -> dict:
|
|
351
|
+
"""Update a PR title or body (operator+).
|
|
352
|
+
|
|
353
|
+
Raises :class:`ValidationError` (422) on a ``ValueError`` (matching legacy).
|
|
354
|
+
"""
|
|
355
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
356
|
+
|
|
357
|
+
from core.api.services import pr_service
|
|
358
|
+
|
|
359
|
+
try:
|
|
360
|
+
return await pr_service.update_pr(task_id, db, title=title, body=body)
|
|
361
|
+
except ValueError as exc:
|
|
362
|
+
raise ValidationError(code="update_pr_failed", message=str(exc))
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
async def revert_pull_request(
|
|
366
|
+
ctx: CallerContext,
|
|
367
|
+
db: aiosqlite.Connection,
|
|
368
|
+
*,
|
|
369
|
+
task_id: str,
|
|
370
|
+
) -> dict:
|
|
371
|
+
"""Revert a merged PR — creates a new task + new PR with a git revert commit
|
|
372
|
+
(operator+). HUMAN-ONLY gate at the HTTP ``Depends`` (see module docstring),
|
|
373
|
+
not re-checked here.
|
|
374
|
+
|
|
375
|
+
Writes a ``pr.revert`` audit entry on success. Raises :class:`ValidationError`
|
|
376
|
+
(422) on a ``ValueError`` and re-raises :class:`GitOpsError` (-> 500).
|
|
377
|
+
"""
|
|
378
|
+
require_role_ctx(ctx, "operator", "admin", "super_admin")
|
|
379
|
+
|
|
380
|
+
from core.api.services import pr_service
|
|
381
|
+
from core.api.services.audit import log_audit
|
|
382
|
+
|
|
383
|
+
try:
|
|
384
|
+
result = await pr_service.revert_pr(task_id, db)
|
|
385
|
+
except ValueError as exc:
|
|
386
|
+
raise ValidationError(code="revert_pr_failed", message=str(exc))
|
|
387
|
+
# GitOpsError propagates; the adapter maps it to the legacy 500.
|
|
388
|
+
|
|
389
|
+
await log_audit(
|
|
390
|
+
db,
|
|
391
|
+
action="pr.revert",
|
|
392
|
+
user=ctx.username,
|
|
393
|
+
resource_type="pull_request",
|
|
394
|
+
resource_id=task_id,
|
|
395
|
+
details={"task_id": task_id},
|
|
396
|
+
)
|
|
397
|
+
return result
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
__all__ = [
|
|
401
|
+
"GitOpsError",
|
|
402
|
+
"MergeConflictError",
|
|
403
|
+
"ServiceError",
|
|
404
|
+
"get_merge_conflicts",
|
|
405
|
+
"get_pull_request",
|
|
406
|
+
"create_branch",
|
|
407
|
+
"register_branch",
|
|
408
|
+
"submit_pull_request",
|
|
409
|
+
"merge_pull_request",
|
|
410
|
+
"approve_pull_request",
|
|
411
|
+
"request_pull_request_changes",
|
|
412
|
+
"close_pull_request",
|
|
413
|
+
"update_pull_request",
|
|
414
|
+
"revert_pull_request",
|
|
415
|
+
]
|