marvisx-cli 0.1.0__tar.gz → 0.2.1__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.
Files changed (603) hide show
  1. {marvisx_cli-0.1.0/marvisx_cli.egg-info → marvisx_cli-0.2.1}/PKG-INFO +4 -1
  2. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/config.py +28 -2
  3. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/db.py +71 -5
  4. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/main.py +8 -2
  5. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/rbac.py +8 -2
  6. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/findings.py +6 -1
  7. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/embedding_service.py +8 -2
  8. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/insert_saga.py +53 -3
  9. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/terminal_metrics_dump.py +30 -11
  10. marvisx_cli-0.2.1/core/api/tests/test_require_scope_empty_deny.py +65 -0
  11. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_safety_bridge.py +57 -0
  12. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/search.py +9 -14
  13. marvisx_cli-0.2.1/core/cli/marvis_account.py +132 -0
  14. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_init.py +41 -8
  15. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_runtime.py +12 -3
  16. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/safety_bridge.py +11 -0
  17. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/telemetry/client.py +1 -1
  18. marvisx_cli-0.2.1/core/telemetry/entitlements.py +26 -0
  19. marvisx_cli-0.2.1/core/telemetry/rollup.py +281 -0
  20. marvisx_cli-0.2.1/core/telemetry/sender.py +224 -0
  21. marvisx_cli-0.2.1/core/wizard/byok_vault.py +384 -0
  22. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1/marvisx_cli.egg-info}/PKG-INFO +4 -1
  23. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/marvisx_cli.egg-info/SOURCES.txt +8 -0
  24. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/marvisx_cli.egg-info/requires.txt +4 -0
  25. marvisx_cli-0.2.1/migrations/144_notifications_pending_sync_index.sql +14 -0
  26. marvisx_cli-0.2.1/migrations/145_audit_log_immutable.sql +23 -0
  27. marvisx_cli-0.2.1/migrations/145_audit_log_immutable_down.sql +4 -0
  28. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/pyproject.toml +13 -1
  29. marvisx_cli-0.1.0/core/wizard/byok_vault.py +0 -147
  30. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/LICENSE +0 -0
  31. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/MANIFEST.in +0 -0
  32. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/README.md +0 -0
  33. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/__init__.py +0 -0
  34. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/agents/__init__.py +0 -0
  35. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/agents/session_health.py +0 -0
  36. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/agents/session_manager.py +0 -0
  37. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/bin/marvisx-state-hook.py +0 -0
  38. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/dependencies/__init__.py +0 -0
  39. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/dependencies/tenant.py +0 -0
  40. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/__init__.py +0 -0
  41. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/_adapter.py +0 -0
  42. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/server.py +0 -0
  43. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/__init__.py +0 -0
  44. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/brain.py +0 -0
  45. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/graph.py +0 -0
  46. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/handoffs.py +0 -0
  47. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/ingest.py +0 -0
  48. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/learnings.py +0 -0
  49. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/projects.py +0 -0
  50. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/pull_requests.py +0 -0
  51. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/safety.py +0 -0
  52. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/search.py +0 -0
  53. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/mcp/tools/tasks.py +0 -0
  54. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/middleware/__init__.py +0 -0
  55. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/middleware/tool_call_audit.py +0 -0
  56. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/__init__.py +0 -0
  57. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/auth.py +0 -0
  58. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/brain.py +0 -0
  59. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/common.py +0 -0
  60. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/costs.py +0 -0
  61. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/graph.py +0 -0
  62. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/graph_cosmo.py +0 -0
  63. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/graph_pr_impact.py +0 -0
  64. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/graph_ux.py +0 -0
  65. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/inbox.py +0 -0
  66. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/ingest_keys.py +0 -0
  67. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/kg.py +0 -0
  68. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/llm_config.py +0 -0
  69. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/monitoring.py +0 -0
  70. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/projects.py +0 -0
  71. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/search.py +0 -0
  72. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/sessions.py +0 -0
  73. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/tasks.py +0 -0
  74. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/teams.py +0 -0
  75. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/models/users.py +0 -0
  76. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/observability/__init__.py +0 -0
  77. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/observability/tracing.py +0 -0
  78. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/paths.py +0 -0
  79. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/rate_limit.py +0 -0
  80. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/__init__.py +0 -0
  81. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/_adapter.py +0 -0
  82. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/admin_pr_impact.py +0 -0
  83. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/admin_settings.py +0 -0
  84. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/agent.py +0 -0
  85. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/agent_tokens.py +0 -0
  86. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/app_settings.py +0 -0
  87. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/audit.py +0 -0
  88. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/auth.py +0 -0
  89. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/bench.py +0 -0
  90. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/brain.py +0 -0
  91. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/brain_directions.py +0 -0
  92. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/ci_checks.py +0 -0
  93. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/comments.py +0 -0
  94. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/costs.py +0 -0
  95. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/docs_coverage.py +0 -0
  96. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/docs_governance.py +0 -0
  97. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/documents.py +0 -0
  98. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/files.py +0 -0
  99. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/finder.py +0 -0
  100. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/graph.py +0 -0
  101. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/handoffs.py +0 -0
  102. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/inbox.py +0 -0
  103. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/ingest_api_keys.py +0 -0
  104. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/ingest_triage.py +0 -0
  105. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/judge.py +0 -0
  106. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/kg.py +0 -0
  107. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/learnings.py +0 -0
  108. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/llm_config.py +0 -0
  109. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/monitoring.py +0 -0
  110. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/notifications.py +0 -0
  111. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/pr_impact.py +0 -0
  112. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/projects.py +0 -0
  113. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/pull_requests.py +0 -0
  114. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/push.py +0 -0
  115. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/raci.py +0 -0
  116. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/search.py +0 -0
  117. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/sessions.py +0 -0
  118. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/settings.py +0 -0
  119. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/share_repo.py +0 -0
  120. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/status_updates.py +0 -0
  121. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/tags.py +0 -0
  122. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/tasks.py +0 -0
  123. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/teams.py +0 -0
  124. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/terminal.py +0 -0
  125. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/users.py +0 -0
  126. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/routers/webhooks.py +0 -0
  127. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/runtime_settings.py +0 -0
  128. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/security.py +0 -0
  129. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/__init__.py +0 -0
  130. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/audit.py +0 -0
  131. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/auto_approval.py +0 -0
  132. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/__init__.py +0 -0
  133. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/baseline.py +0 -0
  134. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/capabilities.py +0 -0
  135. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/cascade_rollup.py +0 -0
  136. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/compound_bridge.py +0 -0
  137. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/cycle.py +0 -0
  138. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/cycle_snapshot.py +0 -0
  139. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/digest_collector.py +0 -0
  140. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/direction.py +0 -0
  141. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/drift.py +0 -0
  142. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/drift_router.py +0 -0
  143. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/edge_metrics.py +0 -0
  144. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/events_reader.py +0 -0
  145. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/findings_reader.py +0 -0
  146. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/jobs.py +0 -0
  147. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/journal.py +0 -0
  148. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/knowledge_forms.py +0 -0
  149. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/__init__.py +0 -0
  150. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/_runner.py +0 -0
  151. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/base.py +0 -0
  152. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/cache.py +0 -0
  153. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/constants.py +0 -0
  154. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/direction_alignment.py +0 -0
  155. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/factory.py +0 -0
  156. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/finding_reasoning.py +0 -0
  157. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/finding_summary.py +0 -0
  158. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/grounding.py +0 -0
  159. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/journal_polish.py +0 -0
  160. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/local_gateway.py +0 -0
  161. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/parsers.py +0 -0
  162. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/llm/router_glue.py +0 -0
  163. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/memory_ops.py +0 -0
  164. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/models.py +0 -0
  165. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/owner_hint.py +0 -0
  166. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/recap.py +0 -0
  167. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/__init__.py +0 -0
  168. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/_signals.py +0 -0
  169. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr1_activity_without_status.py +0 -0
  170. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr2_decision_without_adr.py +0 -0
  171. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr3_stale_open_loop.py +0 -0
  172. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr4_docs_governance_drift.py +0 -0
  173. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr5_playbook_changed.py +0 -0
  174. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr6_external_update_unpropagated.py +0 -0
  175. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr7_claimed_decision_gap.py +0 -0
  176. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/rules/dr8_direction_misalignment.py +0 -0
  177. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/runs_reader.py +0 -0
  178. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/scope.py +0 -0
  179. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/sources/__init__.py +0 -0
  180. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/sources/base.py +0 -0
  181. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/sources/git_kg.py +0 -0
  182. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/sources/handoffs.py +0 -0
  183. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/sources/ingestor.py +0 -0
  184. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/sources/learnings.py +0 -0
  185. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/sources/pir_tasks.py +0 -0
  186. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/watermarks.py +0 -0
  187. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/brain/ws_emitter.py +0 -0
  188. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/cc_tasks_reader.py +0 -0
  189. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ci_service.py +0 -0
  190. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/claude_metrics.py +0 -0
  191. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/codex_metrics.py +0 -0
  192. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/conversation_reader.py +0 -0
  193. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/cost_service.py +0 -0
  194. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/crypto.py +0 -0
  195. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/docs_governance/__init__.py +0 -0
  196. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/docs_governance/confidence.py +0 -0
  197. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/docs_governance/config.py +0 -0
  198. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/docs_governance/enrichment.py +0 -0
  199. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/docs_governance/frontmatter_validator.py +0 -0
  200. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/docs_governance/hard_gates.py +0 -0
  201. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/docs_governance/triage_orchestrator.py +0 -0
  202. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/embedding_internal.py +0 -0
  203. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/event_dispatcher.py +0 -0
  204. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/events.py +0 -0
  205. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/git_ops.py +0 -0
  206. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/graph_cosmo_service.py +0 -0
  207. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/graph_ranker.py +0 -0
  208. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/graph_service.py +0 -0
  209. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox.py +0 -0
  210. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_digest.py +0 -0
  211. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_digest_deep_research.py +0 -0
  212. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_digest_jobs.py +0 -0
  213. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_gmail_sync.py +0 -0
  214. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_llm_classifier.py +0 -0
  215. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_source_identity.py +0 -0
  216. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_sources.py +0 -0
  217. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_taxonomy.py +0 -0
  218. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_tldr.py +0 -0
  219. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/inbox_triage.py +0 -0
  220. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/__init__.py +0 -0
  221. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/api_key_auth.py +0 -0
  222. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/auto_approve.py +0 -0
  223. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/classifier.py +0 -0
  224. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/confidence.py +0 -0
  225. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/dispatch.py +0 -0
  226. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/embedding_router.py +0 -0
  227. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/events.py +0 -0
  228. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/ignore_patterns.py +0 -0
  229. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/image_probe.py +0 -0
  230. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/ingress.py +0 -0
  231. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/__init__.py +0 -0
  232. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/anthropic_haiku.py +0 -0
  233. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/base.py +0 -0
  234. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/byok_provider.py +0 -0
  235. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/classification_context.py +0 -0
  236. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/config_store.py +0 -0
  237. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/factory.py +0 -0
  238. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/kg_enricher.py +0 -0
  239. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/local_gateway.py +0 -0
  240. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/local_vllm.py +0 -0
  241. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/llm/openai_nano.py +0 -0
  242. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/lock_advisory.py +0 -0
  243. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parser_router.py +0 -0
  244. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/__init__.py +0 -0
  245. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/docling_parser.py +0 -0
  246. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/docparse_gateway.py +0 -0
  247. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/docx_parser.py +0 -0
  248. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/folder_unpacker.py +0 -0
  249. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/gateway_aux.py +0 -0
  250. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/image_parser.py +0 -0
  251. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/internal_markdown.py +0 -0
  252. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/ocr_gateway.py +0 -0
  253. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/ocr_pdf_parser.py +0 -0
  254. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/pdf_types.py +0 -0
  255. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/transcript_parser.py +0 -0
  256. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/vision_gateway.py +0 -0
  257. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/xlsx_parser.py +0 -0
  258. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/parsers/zip_unpacker.py +0 -0
  259. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/preflight.py +0 -0
  260. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/retry_voyage.py +0 -0
  261. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/routing_policy.py +0 -0
  262. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/serializers/__init__.py +0 -0
  263. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/serializers/xlsx_to_markdown.py +0 -0
  264. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/skip_log.py +0 -0
  265. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/ingest/watcher.py +0 -0
  266. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/__init__.py +0 -0
  267. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/audit.py +0 -0
  268. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/hybrid_search.py +0 -0
  269. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/lens.py +0 -0
  270. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/pr_impact.py +0 -0
  271. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/queries.py +0 -0
  272. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/ranking.py +0 -0
  273. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg/rrf.py +0 -0
  274. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/kg_watcher_control.py +0 -0
  275. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/local_llm/__init__.py +0 -0
  276. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/local_llm/async_client.py +0 -0
  277. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/local_llm/client.py +0 -0
  278. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/local_llm/url_validator.py +0 -0
  279. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/metrics_collector.py +0 -0
  280. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/metrics_providers.py +0 -0
  281. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/model_registry.py +0 -0
  282. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/model_router.py +0 -0
  283. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/n8n_client.py +0 -0
  284. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/newsletter_llm_gateway.py +0 -0
  285. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/notification_service.py +0 -0
  286. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/openai_responses.py +0 -0
  287. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/opencode_metrics.py +0 -0
  288. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/opencode_sessions.py +0 -0
  289. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pii_redactor.py +0 -0
  290. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_impact_pipeline/__init__.py +0 -0
  291. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_impact_pipeline/differ.py +0 -0
  292. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_impact_pipeline/dispatcher.py +0 -0
  293. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_impact_pipeline/gc.py +0 -0
  294. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_impact_pipeline/languages.py +0 -0
  295. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_impact_pipeline/parser.py +0 -0
  296. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_impact_pipeline/writer.py +0 -0
  297. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/pr_service.py +0 -0
  298. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/project_paths.py +0 -0
  299. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/project_status_updates.py +0 -0
  300. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/providers.py +0 -0
  301. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/push_service.py +0 -0
  302. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/reminder_service.py +0 -0
  303. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/runas.py +0 -0
  304. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/salience_service.py +0 -0
  305. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/security_collector.py +0 -0
  306. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/session_catalog.py +0 -0
  307. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/session_metrics_service.py +0 -0
  308. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/session_ops.py +0 -0
  309. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/session_state.py +0 -0
  310. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/share_links.py +0 -0
  311. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/task_transitions.py +0 -0
  312. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/terminal_metrics.py +0 -0
  313. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/tmux.py +0 -0
  314. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/webhook_service.py +0 -0
  315. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/services/workspace_sync.py +0 -0
  316. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/templates/__init__.py +0 -0
  317. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/templates/markdown_share.py +0 -0
  318. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/terminal.py +0 -0
  319. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/__init__.py +0 -0
  320. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_agent_facing_auth_dependencies.py +0 -0
  321. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_audit_permissions.py +0 -0
  322. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_backfill_session_conversations.py +0 -0
  323. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_backfill_working_seconds_msg.py +0 -0
  324. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_claude_metrics.py +0 -0
  325. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_codex_metrics.py +0 -0
  326. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_finder_paths.py +0 -0
  327. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_git_ops_merge.py +0 -0
  328. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_learnings_check_search.py +0 -0
  329. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_metrics_providers.py +0 -0
  330. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_migration_087.py +0 -0
  331. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_migration_088.py +0 -0
  332. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_migration_089.py +0 -0
  333. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_openai_responses.py +0 -0
  334. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_opencode_metrics.py +0 -0
  335. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_opencode_sessions.py +0 -0
  336. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_pr_workflow_e2e.py +0 -0
  337. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_projects_handoffs.py +0 -0
  338. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_providers.py +0 -0
  339. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_session_catalog.py +0 -0
  340. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_session_conversations.py +0 -0
  341. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_session_metrics_service.py +0 -0
  342. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_session_resume_paths.py +0 -0
  343. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_session_theme_mode_migration.py +0 -0
  344. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_sessions_rbac.py +0 -0
  345. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_share_edit.py +0 -0
  346. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_share_repo.py +0 -0
  347. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_terminal_session_manager.py +0 -0
  348. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_terminal_upload.py +0 -0
  349. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_tmux.py +0 -0
  350. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_workspace_sync.py +0 -0
  351. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/tests/test_ws_ticket_in_memory.py +0 -0
  352. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/__init__.py +0 -0
  353. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/_context.py +0 -0
  354. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/_errors.py +0 -0
  355. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/_roles.py +0 -0
  356. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/audit.py +0 -0
  357. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/brain.py +0 -0
  358. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/costs.py +0 -0
  359. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/graph.py +0 -0
  360. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/handoffs.py +0 -0
  361. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/ingest_triage.py +0 -0
  362. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/learnings.py +0 -0
  363. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/projects.py +0 -0
  364. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/pull_requests.py +0 -0
  365. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/use_cases/tasks.py +0 -0
  366. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/api/visibility.py +0 -0
  367. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/README.md +0 -0
  368. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/__init__.py +0 -0
  369. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/_index_source.py +0 -0
  370. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/_runtime_ctx.py +0 -0
  371. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/_transmute.py +0 -0
  372. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_doctor.py +0 -0
  373. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_feedback.py +0 -0
  374. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_governance.py +0 -0
  375. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_hooks.py +0 -0
  376. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_mcp.py +0 -0
  377. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/cli/marvis_telemetry.py +0 -0
  378. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/_drift_check.py +0 -0
  379. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/_frontmatter.py +0 -0
  380. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/_graph_writer.py +0 -0
  381. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/ast_parser.py +0 -0
  382. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/__init__.py +0 -0
  383. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/_config.sh +0 -0
  384. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/block-dangerous-bash.sh +0 -0
  385. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/block-db-direct-write.sh +0 -0
  386. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/block-push-no-task.sh +0 -0
  387. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/block-staging-to-prod.sh +0 -0
  388. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/block-subtree-push.sh +0 -0
  389. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/config.json +0 -0
  390. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/enforce-no-merge-main.sh +0 -0
  391. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/enforce-worktree.sh +0 -0
  392. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/quality-gate.sh +0 -0
  393. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/safety_bridge.py +0 -0
  394. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/install_hooks/secret-scan.sh +0 -0
  395. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/migrate_spike_node_ids.py +0 -0
  396. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/populate_artifacts.py +0 -0
  397. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/populate_cross_project.py +0 -0
  398. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/populate_inbox_nodes.py +0 -0
  399. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/populate_pr_impact.py +0 -0
  400. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/populate_project_nodes.py +0 -0
  401. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/populate_touch_counter.py +0 -0
  402. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/scripts/reparse_failed.py +0 -0
  403. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/telemetry/__init__.py +0 -0
  404. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/telemetry/schema.py +0 -0
  405. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/wizard/__init__.py +0 -0
  406. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/wizard/defaults.py +0 -0
  407. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/wizard/state.py +0 -0
  408. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/wizard/steps.py +0 -0
  409. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/core/wizard/validation.py +0 -0
  410. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/marvisx_cli.egg-info/dependency_links.txt +0 -0
  411. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/marvisx_cli.egg-info/entry_points.txt +0 -0
  412. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/marvisx_cli.egg-info/top_level.txt +0 -0
  413. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/001_initial.sql +0 -0
  414. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/002_tasks.sql +0 -0
  415. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/003_session_management.sql +0 -0
  416. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/004_projects_comments.sql +0 -0
  417. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/005_session_intelligence.sql +0 -0
  418. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/006_settings.sql +0 -0
  419. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/007_task_scoring.sql +0 -0
  420. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/008_cost_tracking.sql +0 -0
  421. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/009_session_card_metrics.sql +0 -0
  422. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/010_monitoring.sql +0 -0
  423. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/012_agent_api.sql +0 -0
  424. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/013_session_complete.sql +0 -0
  425. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/015_pull_requests.sql +0 -0
  426. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/015_pull_requests_down.sql +0 -0
  427. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/016_users_raci.sql +0 -0
  428. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/017_task_cost_entries.sql +0 -0
  429. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/018_agents.sql +0 -0
  430. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/018_agents_down.sql +0 -0
  431. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/019_review_feedback.sql +0 -0
  432. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/020_pr_commit_sha.sql +0 -0
  433. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/021_webhook_events.sql +0 -0
  434. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/022_devx_agent_managed.sql +0 -0
  435. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/022_devx_agent_managed_down.sql +0 -0
  436. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/023_devx_p1_gate.sql +0 -0
  437. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/023_devx_p1_gate_down.sql +0 -0
  438. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/024_chat_messages.sql +0 -0
  439. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/024_pr_conversation_id.sql +0 -0
  440. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/024_task_indexes.sql +0 -0
  441. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/024_task_indexes_down.sql +0 -0
  442. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/025_audit_log.sql +0 -0
  443. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/026_agent_tokens.sql +0 -0
  444. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/027_teams_auth_phase_b.sql +0 -0
  445. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/028_learnings.sql +0 -0
  446. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/029_team_roles.sql +0 -0
  447. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/030_finder_pins.sql +0 -0
  448. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/031_pr_deploy_status.sql +0 -0
  449. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/032_task_reminders.sql +0 -0
  450. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/033_events_retry_count.sql +0 -0
  451. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/033_session_owner.sql +0 -0
  452. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/034_notifications.sql +0 -0
  453. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/035_shared_links.sql +0 -0
  454. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/036_session_index_upgrade.sql +0 -0
  455. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/037_pr_approval.sql +0 -0
  456. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/038_pr_submitted_by.sql +0 -0
  457. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/039_push_subscriptions.sql +0 -0
  458. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/040_semantic_search.sql +0 -0
  459. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/041_workspaces.sql +0 -0
  460. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/042_oidc_providers.sql +0 -0
  461. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/043_ci_checks.sql +0 -0
  462. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/044_agent_metrics.sql +0 -0
  463. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/045_documents_doc_type.sql +0 -0
  464. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/046_salience.sql +0 -0
  465. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/047_seed_missing_agents.sql +0 -0
  466. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/048_fix_agent_paths_roles.sql +0 -0
  467. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/049_agent_role_and_learnings_schema.sql +0 -0
  468. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/050_session_provider.sql +0 -0
  469. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/051_session_launch_profile.sql +0 -0
  470. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/052_session_theme_mode.sql +0 -0
  471. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/052_task_kind.sql +0 -0
  472. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/053_inbox_items.sql +0 -0
  473. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/054_inbox_triage_contract.sql +0 -0
  474. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/055_inbox_topic_treatment.sql +0 -0
  475. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/056_inbox_treatment_read_save.sql +0 -0
  476. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/057_session_theme_mode_backfill.sql +0 -0
  477. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/058_inbox_item_status_lifecycle.sql +0 -0
  478. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/059_inbox_tldr_and_source_scores.sql +0 -0
  479. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/060_newsletter.sql +0 -0
  480. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/061_inbox_redesign.sql +0 -0
  481. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/062_fix_inbox_sources_backfill.sql +0 -0
  482. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/063_task_completion_mode.sql +0 -0
  483. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/064_judge_mode_setting.sql +0 -0
  484. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/065_knowledge_graph_spike.sql +0 -0
  485. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/066_digest_ranking_inputs.sql +0 -0
  486. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/066_kg_artifact_nodes.sql +0 -0
  487. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/067_inbox_digest_selections.sql +0 -0
  488. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/067_kg_temporal.sql +0 -0
  489. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/068_inbox_digest_app_settings.sql +0 -0
  490. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/068_kg_touch_counter.sql +0 -0
  491. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/069_kg_doc_types.sql +0 -0
  492. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/070_digest_ranking_inputs_recovery.sql +0 -0
  493. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/071_inbox_digest_selections_recovery.sql +0 -0
  494. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/072_inbox_digest_app_settings_recovery.sql +0 -0
  495. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/073_kg_cross_project.sql +0 -0
  496. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/073_kg_cross_project_down.sql +0 -0
  497. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/074_kg_infra_types.sql +0 -0
  498. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/074_kg_infra_types_down.sql +0 -0
  499. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/075_kg_file_state_recovery.sql +0 -0
  500. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/075_kg_file_state_recovery_down.sql +0 -0
  501. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/076_kg_watcher_state.sql +0 -0
  502. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/076_kg_watcher_state_down.sql +0 -0
  503. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/077_kg_doc_types_extend.sql +0 -0
  504. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/077_kg_doc_types_extend_down.sql +0 -0
  505. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/078_kg_fts5.sql +0 -0
  506. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/078_kg_fts5_down.sql +0 -0
  507. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/079_kg_missing_indexes.sql +0 -0
  508. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/079_kg_missing_indexes_down.sql +0 -0
  509. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/080_kg_fts5_extended.sql +0 -0
  510. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/080_kg_fts5_extended_down.sql +0 -0
  511. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/081_kg_lens_indexes.sql +0 -0
  512. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/081_kg_lens_indexes_down.sql +0 -0
  513. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/082_kg_pins.sql +0 -0
  514. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/082_kg_pins_down.sql +0 -0
  515. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/083_kg_graph_nodes_degree.sql +0 -0
  516. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/083_kg_graph_nodes_degree_down.sql +0 -0
  517. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/084_drop_legacy_scheduler_tables.sql +0 -0
  518. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/084_drop_legacy_scheduler_tables_down.sql +0 -0
  519. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/085_kg_edge_resolves_to.sql +0 -0
  520. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/085_kg_edge_resolves_to_down.sql +0 -0
  521. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/086_project_status_updates_feed.sql +0 -0
  522. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/086_project_status_updates_feed_down.sql +0 -0
  523. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/087_session_metrics_dual.sql +0 -0
  524. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/087_session_metrics_dual_down.sql +0 -0
  525. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/088_rename_context_pct_legacy.sql +0 -0
  526. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/088_rename_context_pct_legacy_down.sql +0 -0
  527. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/089_session_metrics_equivalent_cost.sql +0 -0
  528. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/089_session_metrics_equivalent_cost_down.sql +0 -0
  529. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/090_kg_inbox_node_type.sql +0 -0
  530. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/090_kg_inbox_node_type_down.sql +0 -0
  531. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/091_kg_inbox_node_type_check.sql +0 -0
  532. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/091_kg_inbox_node_type_check_down.sql +0 -0
  533. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/092_sessions_activity_state_ts.sql +0 -0
  534. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/092_sessions_activity_state_ts_down.sql +0 -0
  535. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/093_sessions_activity_state_column.sql +0 -0
  536. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/093_sessions_activity_state_column_down.sql +0 -0
  537. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/094_ingest_pending.sql +0 -0
  538. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/094_ingest_pending_down.sql +0 -0
  539. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/095_kg_intent_first.sql +0 -0
  540. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/095_kg_intent_first_down.sql +0 -0
  541. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/096_kg_xlsx_artifact_prefix.sql +0 -0
  542. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/096_kg_xlsx_artifact_prefix_down.sql +0 -0
  543. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/097_ingest_change_history.sql +0 -0
  544. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/097_ingest_change_history_down.sql +0 -0
  545. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/098_kg_node_type_business.sql +0 -0
  546. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/098_kg_node_type_business_down.sql +0 -0
  547. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/099_kg_edges_restore_weight.sql +0 -0
  548. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/099_kg_edges_restore_weight_down.sql +0 -0
  549. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/100_kg_enriched_at.sql +0 -0
  550. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/100_kg_enriched_at_down.sql +0 -0
  551. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/101_local_llm_shadow_comparisons.sql +0 -0
  552. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/101_local_llm_shadow_comparisons_down.sql +0 -0
  553. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/102_promote_llm_costs.sql +0 -0
  554. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/102_promote_llm_costs_down.sql +0 -0
  555. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/103_ingest_skipped_log.sql +0 -0
  556. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/103_ingest_skipped_log_down.sql +0 -0
  557. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/120_docs_governance.sql +0 -0
  558. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/120_docs_governance_down.sql +0 -0
  559. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/121_notification_event_fk_cleanup.sql +0 -0
  560. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/121_notification_event_fk_cleanup_down.sql +0 -0
  561. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/122_docs_drift_history.sql +0 -0
  562. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/122_docs_drift_history_down.sql +0 -0
  563. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/123_ingest_parser_waiting_status.sql +0 -0
  564. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/123_ingest_parser_waiting_status_down.sql +0 -0
  565. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/124_heypocket_recordings.sql +0 -0
  566. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/124_heypocket_recordings_down.sql +0 -0
  567. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/125_kg_node_type_record.sql +0 -0
  568. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/125_kg_node_type_record_down.sql +0 -0
  569. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/126_ingest_terminal_upload_source_kind.sql +0 -0
  570. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/126_ingest_terminal_upload_source_kind_down.sql +0 -0
  571. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/127_brain_v1_substrate.sql +0 -0
  572. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/127_brain_v1_substrate_down.sql +0 -0
  573. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/128_brain_drift_signals.sql +0 -0
  574. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/128_brain_drift_signals_down.sql +0 -0
  575. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/129_brain_memory_operations.sql +0 -0
  576. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/129_brain_memory_operations_down.sql +0 -0
  577. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/130_brain_findings.sql +0 -0
  578. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/130_brain_findings_down.sql +0 -0
  579. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/132_kg_pr_modifies.sql +0 -0
  580. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/132_kg_pr_modifies_down.sql +0 -0
  581. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/133_brain_v1_2_direction_schema.sql +0 -0
  582. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/133_brain_v1_2_direction_schema_down.sql +0 -0
  583. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/134_brain_journal_narrative_polished.sql +0 -0
  584. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/134_brain_journal_narrative_polished_down.sql +0 -0
  585. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/135_kg_edges_provider.sql +0 -0
  586. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/136_documents_fts.sql +0 -0
  587. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/137_promote_llm_costs.sql +0 -0
  588. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/137_promote_llm_costs_down.sql +0 -0
  589. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/138_ingest_api_keys.sql +0 -0
  590. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/138_ingest_api_keys_down.sql +0 -0
  591. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/139_ingest_pending_ingress.sql +0 -0
  592. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/139_ingest_pending_ingress_down.sql +0 -0
  593. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/140_ingest_idempotency_quota.sql +0 -0
  594. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/140_ingest_idempotency_quota_down.sql +0 -0
  595. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/141_ingest_pending_metadata.sql +0 -0
  596. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/141_ingest_pending_metadata_down.sql +0 -0
  597. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/142_llm_function_config.sql +0 -0
  598. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/142_llm_function_config_down.sql +0 -0
  599. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/143_kg_code_embeddings.sql +0 -0
  600. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/143_kg_code_embeddings_down.sql +0 -0
  601. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/migrations/__init__.py +0 -0
  602. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/projects/_template/project.yaml +0 -0
  603. {marvisx_cli-0.1.0 → marvisx_cli-0.2.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marvisx-cli
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: MarvisX OSS — agent-native company-brain CLI runtime (init, status, brief, triage)
5
5
  Author: MarvisX maintainers
6
6
  License: BSL-1.1
@@ -68,9 +68,12 @@ Requires-Dist: tokenizers>=0.20
68
68
  Requires-Dist: huggingface-hub>=0.24
69
69
  Requires-Dist: numpy>=1.26
70
70
  Requires-Dist: psutil>=5.9.0
71
+ Requires-Dist: sqlite-vec>=0.1.6
71
72
  Provides-Extra: dev
72
73
  Requires-Dist: pytest>=8; extra == "dev"
73
74
  Requires-Dist: pytest-cov>=5; extra == "dev"
75
+ Provides-Extra: keyring
76
+ Requires-Dist: keyring>=24; extra == "keyring"
74
77
  Dynamic: license-file
75
78
 
76
79
  # marvis init
@@ -8,6 +8,29 @@ from typing import Literal
8
8
  from pydantic import AliasChoices, Field, SecretStr
9
9
  from pydantic_settings import BaseSettings, SettingsConfigDict
10
10
 
11
+ # Prod (Hetzner/Docker) ships the vec0 loadable at this path; it stays the
12
+ # final fallback so prod keeps working unchanged.
13
+ _VEC0_PATH_PROD_DEFAULT = "/data/pir/lib/vec0"
14
+
15
+
16
+ def _default_vec0_path() -> str:
17
+ """Resolve the vec0 loadable path for sqlite-vec.
18
+
19
+ Order:
20
+ 1. ``$VEC0_PATH`` env — handled by pydantic-settings (overrides this
21
+ default_factory when set), so it is NOT re-read here.
22
+ 2. The installed ``sqlite_vec`` package's bundled loadable
23
+ (``sqlite_vec.loadable_path()``) — the OSS clean-install path
24
+ (`pip install sqlite-vec`), platform-correct (.so / .dylib).
25
+ 3. ``/data/pir/lib/vec0`` — prod fallback.
26
+ """
27
+ try:
28
+ import sqlite_vec # type: ignore
29
+
30
+ return str(sqlite_vec.loadable_path())
31
+ except Exception: # noqa: BLE001 — missing/old package → prod fallback
32
+ return _VEC0_PATH_PROD_DEFAULT
33
+
11
34
 
12
35
  class Settings(BaseSettings):
13
36
  model_config = SettingsConfigDict(
@@ -381,8 +404,11 @@ class Settings(BaseSettings):
381
404
  # Voyage AI embeddings
382
405
  voyage_api_key: str = ""
383
406
 
384
- # sqlite-vec
385
- vec0_path: str = "/data/pir/lib/vec0"
407
+ # sqlite-vec: env VEC0_PATH → sqlite_vec.loadable_path() → prod fallback.
408
+ vec0_path: str = Field(
409
+ default_factory=_default_vec0_path,
410
+ validation_alias=AliasChoices("VEC0_PATH"),
411
+ )
386
412
 
387
413
  # LifeOS
388
414
  lifeos_data_dir: str = ""
@@ -101,6 +101,7 @@ _write_lock = asyncio.Lock()
101
101
 
102
102
  WRITER_LOCK_EVENT_LIMIT = 500
103
103
  WRITER_LOCK_SLOW_WAIT_MS = 50.0
104
+ WRITER_LOCK_SLOW_HOLD_MS = 1000.0 # Fase 0: log writer holds >1s to separate offenders from queued victims
104
105
  _writer_metrics_lock = Lock()
105
106
  _writer_wait_events: deque[dict[str, Any]] = deque(maxlen=WRITER_LOCK_EVENT_LIMIT)
106
107
  _writer_hold_events: deque[dict[str, Any]] = deque(maxlen=WRITER_LOCK_EVENT_LIMIT)
@@ -291,7 +292,14 @@ def _start_writer_hold(
291
292
  "blocked_by": blocked_by,
292
293
  }
293
294
  )
294
- return holder
295
+ if wait_ms >= WRITER_LOCK_SLOW_WAIT_MS:
296
+ logger.warning(
297
+ "SQLite writer lock WAIT %.0fms for %s (blocked_by=%s)",
298
+ wait_ms,
299
+ label,
300
+ (blocked_by or {}).get("label"),
301
+ )
302
+ return holder
295
303
 
296
304
 
297
305
  def _finish_writer_hold(holder: dict[str, Any]) -> None:
@@ -312,6 +320,13 @@ def _finish_writer_hold(holder: dict[str, Any]) -> None:
312
320
  "blocked_by": holder.get("blocked_by"),
313
321
  }
314
322
  )
323
+ if hold_ms >= WRITER_LOCK_SLOW_HOLD_MS:
324
+ logger.warning(
325
+ "SQLite writer lock HELD %.0fms by %s (waited %.0fms) — offender, not victim",
326
+ hold_ms,
327
+ holder["label"],
328
+ holder.get("wait_ms", 0.0),
329
+ )
315
330
 
316
331
 
317
332
  def get_writer_lock_snapshot(window_seconds: float = 60.0) -> dict[str, Any]:
@@ -494,18 +509,69 @@ async def wal_checkpoint() -> tuple[int, int, int]:
494
509
  # sqlite-vec support
495
510
  _vec_table_ready = False
496
511
 
512
+ # Platform-specific loadable-extension suffixes. The vec0 loadable is `.so` on
513
+ # Linux (prod), `.dylib` on macOS, `.dll` on Windows.
514
+ _VEC0_SUFFIXES = (".so", ".dylib", ".dll")
515
+
516
+
517
+ def resolve_vec0_loadable() -> tuple[str | None, bool]:
518
+ """Resolve the vec0 loadable path, cross-platform.
519
+
520
+ Returns ``(load_arg, found)`` where ``load_arg`` is the argument to pass to
521
+ ``SELECT load_extension(?)`` and ``found`` is True when a real loadable file
522
+ exists on disk.
523
+
524
+ Resolution (prod-safe by construction):
525
+ 1. ``settings.vec0_path`` when it resolves to a real file: if it already
526
+ carries a known suffix use it as-is, otherwise probe ``.so`` /
527
+ ``.dylib`` / ``.dll``. Prod (Linux, ``/data/pir/lib/vec0`` →
528
+ ``vec0.so``, set via ``VEC0_PATH``) resolves here and keeps using the
529
+ exact configured path.
530
+ 2. Else the installed ``sqlite_vec`` package's own loadable
531
+ (``sqlite_vec.loadable_path()``) — the OSS clean-install path, where
532
+ ``/data/pir/lib/vec0`` is absent and the bundled loadable is
533
+ platform-correct (.dylib on macOS, no longer rejected by a hardcoded
534
+ ``.so`` check).
535
+
536
+ The suffix-less ``load_arg`` lets SQLite append the platform suffix itself.
537
+ """
538
+ vec_path = Path(settings.vec0_path)
539
+ if vec_path.suffix:
540
+ if vec_path.exists():
541
+ return (str(vec_path), True)
542
+ else:
543
+ for suffix in _VEC0_SUFFIXES:
544
+ if vec_path.with_suffix(suffix).exists():
545
+ # Pass the suffix-less path; SQLite appends the platform suffix.
546
+ return (str(vec_path), True)
547
+
548
+ try:
549
+ import sqlite_vec # type: ignore
550
+
551
+ pkg_path = Path(str(sqlite_vec.loadable_path()))
552
+ if pkg_path.exists():
553
+ return (str(pkg_path), True)
554
+ # loadable_path() returns a suffix-less base on some builds; probe.
555
+ for suffix in _VEC0_SUFFIXES:
556
+ if pkg_path.with_suffix(suffix).exists():
557
+ return (str(pkg_path), True)
558
+ except Exception: # noqa: BLE001 — package missing/old → settings path is final
559
+ pass
560
+
561
+ # Nothing resolved; return the configured path so callers log a clear miss.
562
+ return (str(vec_path), False)
563
+
497
564
 
498
565
  async def ensure_vec_documents(db: aiosqlite.Connection) -> bool:
499
566
  """Load sqlite-vec on an existing connection and ensure vec_documents exists."""
500
567
  global _vec_table_ready
501
- vec_path = Path(settings.vec0_path)
502
- vec_so = vec_path.with_suffix(".so") if not vec_path.suffix else vec_path
503
- if not vec_so.exists():
568
+ load_arg, found = resolve_vec0_loadable()
569
+ if not found or load_arg is None:
504
570
  return False
505
571
 
506
572
  if not getattr(db, "_pir_vec_extension_loaded", False):
507
573
  await db._execute(db._conn.enable_load_extension, True)
508
- await db.execute("SELECT load_extension(?)", [str(vec_path)])
574
+ await db.execute("SELECT load_extension(?)", [load_arg])
509
575
  setattr(db, "_pir_vec_extension_loaded", True)
510
576
  if not _vec_table_ready:
511
577
  await db.execute("""
@@ -870,11 +870,17 @@ async def _notifications_acted_at_sync_loop() -> None:
870
870
  async with write_db() as db:
871
871
  now = datetime.now(timezone.utc).isoformat()
872
872
  await db.execute(
873
+ # Drive off the small still-pending set + idx_notifications_pending_sync
874
+ # (migration 144): NOT IN (pending) is sargable, the prior
875
+ # `!= 'pending'` forced a full scan -> ~15s writer-lock hold.
876
+ # A target_id pointing at a deleted task is now acted too (benign:
877
+ # the task is no longer pending). tasks.id is PK so no NULL in the
878
+ # subquery -> NOT IN is safe.
873
879
  """UPDATE notifications
874
880
  SET acted_at = ?, read_at = COALESCE(read_at, ?)
875
881
  WHERE acted_at IS NULL AND type = 'task_pending'
876
- AND target_type = 'task' AND target_id IN (
877
- SELECT id FROM tasks WHERE status != 'pending'
882
+ AND target_type = 'task' AND target_id NOT IN (
883
+ SELECT id FROM tasks WHERE status = 'pending'
878
884
  )""",
879
885
  (now, now),
880
886
  )
@@ -80,9 +80,15 @@ def require_scope(*required_scopes: str) -> Callable[..., Awaitable[UserInfo]]:
80
80
  if not user.username.startswith("agent:") and user.username not in agent_usernames:
81
81
  return user
82
82
 
83
- # Agent with no scopes defined = unrestricted (backward compat with existing tokens)
83
+ # Agent with no scopes (empty/null) = NO permission for scope-gated ops.
84
+ # Empty MUST deny, not allow-all: an unscoped agent token previously
85
+ # passed every scope check (authz bypass — empty list satisfied
86
+ # `not user.scopes`). Scope-gated endpoints require an explicit grant.
84
87
  if not user.scopes:
85
- return user
88
+ raise HTTPException(
89
+ status_code=403,
90
+ detail=f"Token missing required scopes: {list(required_scopes)}",
91
+ )
86
92
 
87
93
  # Check that all required scopes are present
88
94
  missing = [s for s in required_scopes if s not in user.scopes]
@@ -1299,7 +1299,12 @@ async def emit_finding_dedup(
1299
1299
  return (finding_id, False)
1300
1300
 
1301
1301
  # INSERT path
1302
- finding_id = f"fnd_{uuid.uuid4().hex[:24]}"
1302
+ # Finding.finding_id requires exactly 32 chars (min_length=32,
1303
+ # max_length=32), matching the BLAKE2b-16 hex sibling ids
1304
+ # (signal_id/operation_id/event_id). Keep the "fnd_" prefix and pad to
1305
+ # 32 total chars (4 prefix + 28 hex) so every findings endpoint
1306
+ # validates instead of 500-ing.
1307
+ finding_id = f"fnd_{uuid.uuid4().hex[:28]}"
1303
1308
  now_iso = _utc_iso(datetime.now(timezone.utc))
1304
1309
  if expires_at is None:
1305
1310
  expires_iso = _utc_iso(
@@ -482,9 +482,15 @@ async def embed_task_document(
482
482
 
483
483
 
484
484
  async def _ensure_vec_documents(db: aiosqlite.Connection, vec0_path: str) -> None:
485
- vec_path = str(Path(vec0_path))
485
+ # Prefer the shared cross-platform resolver (sqlite_vec package loader /
486
+ # .so / .dylib probe) so macOS (.dylib) loads; fall back to the passed path.
487
+ from core.api.db import resolve_vec0_loadable
488
+
489
+ load_arg, found = resolve_vec0_loadable()
490
+ if not found or load_arg is None:
491
+ load_arg = str(Path(vec0_path))
486
492
  await db._execute(db._conn.enable_load_extension, True)
487
- await db.execute("SELECT load_extension(?)", [vec_path])
493
+ await db.execute("SELECT load_extension(?)", [load_arg])
488
494
  await db.execute("""
489
495
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_documents USING vec0(
490
496
  doc_id INTEGER PRIMARY KEY,
@@ -20,8 +20,57 @@ from core.api.services.ingest.events import broadcast_ingest_changed
20
20
 
21
21
  logger = logging.getLogger(__name__)
22
22
 
23
+ # Prod default (Docker): /data/projects exists, so the resolved value stays
24
+ # /data/projects there. Kept as a module-level attribute (not inlined) so it
25
+ # remains an explicit override point — tests monkeypatch it, and a future
26
+ # runtime hook could set it directly. _projects_root() treats any non-default
27
+ # value here as authoritative.
23
28
  PROJECTS_ROOT = Path("/data/projects")
24
29
  REPO_ROOT = repo_root(__file__)
30
+
31
+
32
+ def _projects_root() -> Path:
33
+ """Resolve the projects root the same way the rest of the runtime does.
34
+
35
+ Order (prod-safe by construction):
36
+ 1. The module-level ``PROJECTS_ROOT`` when it has been overridden from its
37
+ ``/data/projects`` default (tests monkeypatch it; a runtime hook may
38
+ set it). An explicit override always wins.
39
+ 2. ``$MARVIS_PROJECTS_ROOT`` (canonical override, see wizard/defaults.py).
40
+ Prod does NOT set it, so prod is unaffected.
41
+ 3. The runtime-applied project dirs (``PROJECT_DIRS[0]``), which
42
+ ``runtime_settings.apply_marvis_settings`` populates from
43
+ ``~/.marvis/settings.yaml`` ``storage.projects_root`` — but ONLY when
44
+ ``/data/projects`` does NOT exist, so prod (where it does) keeps using
45
+ ``/data/projects`` rather than the DB-loaded ``~/workspace/projects``.
46
+ 4. ``/data/projects`` default.
47
+
48
+ Resolved lazily per-call: the API process applies settings.yaml AFTER this
49
+ module imports, so reading at import time would lock in the bare default.
50
+ """
51
+ default_root = Path("/data/projects")
52
+
53
+ # 1. Explicit module-level override (tests / runtime hook).
54
+ if PROJECTS_ROOT != default_root:
55
+ return Path(PROJECTS_ROOT).expanduser().resolve()
56
+
57
+ # 2. Canonical env override (OSS non-Docker).
58
+ env_root = os.environ.get("MARVIS_PROJECTS_ROOT")
59
+ if env_root:
60
+ return Path(env_root).expanduser().resolve()
61
+
62
+ # 3. Runtime settings (settings.yaml → PROJECT_DIRS) on non-Docker installs.
63
+ if not default_root.exists():
64
+ try:
65
+ from core.api.routers.projects import PROJECT_DIRS
66
+
67
+ if PROJECT_DIRS:
68
+ return Path(PROJECT_DIRS[0]).expanduser().resolve()
69
+ except Exception: # noqa: BLE001 — never let resolution crash the saga
70
+ pass
71
+
72
+ # 4. Prod Docker default.
73
+ return default_root.resolve()
25
74
  SUBPROCESS_TIMEOUT_SEC = 60
26
75
 
27
76
  # Phase 1.5 E6: keep-ref so fire-and-forget background tasks don't get GC'd
@@ -53,7 +102,7 @@ ProjectType = Literal["work", "code", "system"]
53
102
 
54
103
 
55
104
  def _project_root(slug: str) -> Path:
56
- return (PROJECTS_ROOT / slug).resolve()
105
+ return (_projects_root() / slug).resolve()
57
106
 
58
107
 
59
108
  def _load_project_entry(slug: str) -> tuple[ProjectType, Path | None]:
@@ -418,12 +467,13 @@ async def _ensure_kg_edge(
418
467
  },
419
468
  ensure_ascii=False,
420
469
  )
470
+ projects_root = _projects_root()
421
471
  candidate_paths = [
422
472
  str(target_path),
423
- str(target_path.relative_to(PROJECTS_ROOT)),
473
+ str(target_path.relative_to(projects_root)),
424
474
  ]
425
475
  if project_slug == "marvisx":
426
- candidate_paths.append(f"projects/{target_path.relative_to(PROJECTS_ROOT)}")
476
+ candidate_paths.append(f"projects/{target_path.relative_to(projects_root)}")
427
477
 
428
478
  async with acquire_write_db() as db:
429
479
  await db.execute(
@@ -32,6 +32,22 @@ INTERNET_PROBE_TARGETS = (
32
32
  )
33
33
 
34
34
 
35
+ _PROBE_DISABLED_VALUES = {"0", "off", "false", "no"}
36
+
37
+
38
+ def network_probe_enabled() -> bool:
39
+ """Whether the periodic internet probe (cloudflare.com/cdn-cgi/trace) runs.
40
+
41
+ Gated by ``$MARVIS_NETWORK_PROBE``: values in {0, off, false, no}
42
+ (case-insensitive) disable the probe — this is what makes an "offline mode"
43
+ honest. Default (env unset / any other value) = ON, so prod is unchanged.
44
+ """
45
+ raw = os.environ.get("MARVIS_NETWORK_PROBE")
46
+ if raw is None:
47
+ return True
48
+ return raw.strip().lower() not in _PROBE_DISABLED_VALUES
49
+
50
+
35
51
  def terminal_metrics_path(
36
52
  *,
37
53
  now: datetime | None = None,
@@ -175,17 +191,20 @@ async def terminal_metrics_background_loop(
175
191
  collector.record_event_loop_lag(max(0.0, (now - expected_wake) * 1000))
176
192
 
177
193
  if now >= next_probe_at:
178
- try:
179
- probe = await sample_internet_probe(collector)
180
- await append_terminal_metrics_record(
181
- {
182
- "kind": "internet_probe",
183
- "probe": probe,
184
- },
185
- output_dir=output_dir,
186
- )
187
- except Exception:
188
- logger.warning("terminal metrics internet probe failed", exc_info=True)
194
+ if network_probe_enabled():
195
+ try:
196
+ probe = await sample_internet_probe(collector)
197
+ await append_terminal_metrics_record(
198
+ {
199
+ "kind": "internet_probe",
200
+ "probe": probe,
201
+ },
202
+ output_dir=output_dir,
203
+ )
204
+ except Exception:
205
+ logger.warning(
206
+ "terminal metrics internet probe failed", exc_info=True
207
+ )
189
208
  next_probe_at = now + network_interval_seconds
190
209
 
191
210
  if now >= next_dump_at:
@@ -0,0 +1,65 @@
1
+ """Regression: require_scope must DENY agent tokens with empty/null scopes.
2
+
3
+ Audit S4: an agent token with scopes=[] previously satisfied `not user.scopes`
4
+ and was treated as unrestricted (authz bypass — a scope-gated PATCH succeeded
5
+ with an empty-scope token). Empty scopes must grant NO permission.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import pytest
10
+ from fastapi import HTTPException
11
+
12
+ from core.api.models.auth import UserInfo
13
+ from core.api.rbac import require_scope
14
+
15
+
16
+ def _agent(scopes: list[str]) -> UserInfo:
17
+ # "agent:" prefix forces the agent path (not the human cookie bypass).
18
+ return UserInfo(
19
+ username="agent:tester",
20
+ user_id="tok-1",
21
+ system_role="operator",
22
+ user_type="agent",
23
+ scopes=scopes,
24
+ )
25
+
26
+
27
+ def _human(scopes: list[str]) -> UserInfo:
28
+ return UserInfo(
29
+ username="emilio",
30
+ user_id="user-1",
31
+ system_role="operator",
32
+ user_type="human",
33
+ scopes=scopes,
34
+ )
35
+
36
+
37
+ @pytest.mark.asyncio
38
+ async def test_empty_scopes_agent_denied():
39
+ check = require_scope("write")
40
+ with pytest.raises(HTTPException) as exc:
41
+ await check(user=_agent([]))
42
+ assert exc.value.status_code == 403
43
+
44
+
45
+ @pytest.mark.asyncio
46
+ async def test_matching_scope_agent_allowed():
47
+ check = require_scope("write")
48
+ user = await check(user=_agent(["read", "write"]))
49
+ assert user.username == "agent:tester"
50
+
51
+
52
+ @pytest.mark.asyncio
53
+ async def test_missing_scope_agent_denied():
54
+ check = require_scope("write")
55
+ with pytest.raises(HTTPException) as exc:
56
+ await check(user=_agent(["read"]))
57
+ assert exc.value.status_code == 403
58
+
59
+
60
+ @pytest.mark.asyncio
61
+ async def test_human_bypasses_scope_check_even_with_empty_scopes():
62
+ # Cookie/JWT humans are gated by role, not scopes — empty scopes is fine.
63
+ check = require_scope("write")
64
+ user = await check(user=_human([]))
65
+ assert user.username == "emilio"
@@ -345,3 +345,60 @@ def test_bash_action_returns_first_matching_rule(monkeypatch):
345
345
 
346
346
  assert decision.allowed is False
347
347
  assert decision.rule == "bash-merge"
348
+
349
+
350
+ def test_secret_scan_runs_outside_git_repo(monkeypatch):
351
+ """S5a: secret scan must NOT fail open when cwd is not a git repo.
352
+
353
+ Previously resolve_repo_root() returning None silently allowed, so a
354
+ `git commit` of an API_KEY=sk-live-... outside a repo slipped through.
355
+ """
356
+ bridge = _load_bridge_module()
357
+ monkeypatch.setattr(
358
+ bridge, "resolve_repo_root", lambda file_path, cwd=None: None
359
+ )
360
+
361
+ decision = bridge.check_secret_scan(
362
+ "git commit -m 'add config' && export API_KEY=sk-live-abcd1234efgh5678ijkl",
363
+ "/tmp/not-a-repo",
364
+ _config(),
365
+ )
366
+
367
+ assert decision.allowed is False
368
+ assert decision.rule == "secret-scan"
369
+
370
+
371
+ def test_secret_scan_outside_repo_allows_clean_command(monkeypatch):
372
+ """Outside a git repo, a clean commit command (no secret) is still allowed."""
373
+ bridge = _load_bridge_module()
374
+ monkeypatch.setattr(
375
+ bridge, "resolve_repo_root", lambda file_path, cwd=None: None
376
+ )
377
+
378
+ decision = bridge.check_secret_scan(
379
+ "git commit -m 'docs: tidy readme'",
380
+ "/tmp/not-a-repo",
381
+ _config(),
382
+ )
383
+
384
+ assert decision.allowed is True
385
+
386
+
387
+ def test_secret_scan_blocks_secret_in_staged_diff(monkeypatch):
388
+ """In-repo path (unchanged behaviour): secret in staged diff is blocked."""
389
+ bridge = _load_bridge_module()
390
+ monkeypatch.setattr(
391
+ bridge, "resolve_repo_root", lambda file_path, cwd=None: "/repo"
392
+ )
393
+ monkeypatch.setattr(
394
+ bridge,
395
+ "_git_output",
396
+ lambda args, cwd: "+API_KEY=sk-live-abcd1234efgh5678ijkl",
397
+ )
398
+
399
+ decision = bridge.check_secret_scan(
400
+ "git commit -m 'add config'", "/repo", _config()
401
+ )
402
+
403
+ assert decision.allowed is False
404
+ assert decision.rule == "secret-scan"
@@ -225,20 +225,17 @@ async def trigger_reindex(
225
225
 
226
226
  async def _reindex_type(doc_type: str, workspace_id: str) -> dict:
227
227
  """Reindex a single document type. Returns stats dict."""
228
- from pathlib import Path
229
-
230
- from core.api.db import _configure_connection
228
+ from core.api.db import _configure_connection, resolve_vec0_loadable
231
229
 
232
230
  db = await aiosqlite.connect(settings.db_path)
233
231
  await _configure_connection(db)
234
232
  db.row_factory = aiosqlite.Row
235
233
  await db.execute("PRAGMA busy_timeout=60000")
236
234
 
237
- vec_path = Path(settings.vec0_path)
238
- vec_so = vec_path.with_suffix(".so") if not vec_path.suffix else vec_path
239
- if vec_so.exists():
235
+ load_arg, vec_found = resolve_vec0_loadable()
236
+ if vec_found and load_arg is not None:
240
237
  await db._execute(db._conn.enable_load_extension, True)
241
- await db.execute("SELECT load_extension(?)", [str(vec_path)])
238
+ await db.execute("SELECT load_extension(?)", [load_arg])
242
239
  await db.execute("""
243
240
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_documents USING vec0(
244
241
  doc_id INTEGER PRIMARY KEY,
@@ -272,8 +269,7 @@ async def _reindex_all_bg(db_path: str) -> None:
272
269
  Uses a SINGLE connection with vec extension loaded as both db and vec_db.
273
270
  Two separate writers to the same DB cause 'database is locked' errors.
274
271
  """
275
- from pathlib import Path
276
- from core.api.db import _configure_connection
272
+ from core.api.db import _configure_connection, resolve_vec0_loadable
277
273
 
278
274
  logger.info("Reindex all: starting background job")
279
275
  try:
@@ -282,12 +278,11 @@ async def _reindex_all_bg(db_path: str) -> None:
282
278
  db.row_factory = aiosqlite.Row
283
279
  # Higher busy_timeout for background reindex — avoids blocking regular requests
284
280
  await db.execute("PRAGMA busy_timeout=60000")
285
- # Load vec extension on the same connection
286
- vec_path = Path(settings.vec0_path)
287
- vec_so = vec_path.with_suffix(".so") if not vec_path.suffix else vec_path
288
- if vec_so.exists():
281
+ # Load vec extension on the same connection (cross-platform: .so/.dylib)
282
+ load_arg, vec_found = resolve_vec0_loadable()
283
+ if vec_found and load_arg is not None:
289
284
  await db._execute(db._conn.enable_load_extension, True)
290
- await db.execute("SELECT load_extension(?)", [str(vec_path)])
285
+ await db.execute("SELECT load_extension(?)", [load_arg])
291
286
  await db.execute("""
292
287
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_documents USING vec0(
293
288
  doc_id INTEGER PRIMARY KEY,