ouroboros-ai 0.28.8.dev4__tar.gz → 0.28.8.dev9__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.

Potentially problematic release.


This version of ouroboros-ai might be problematic. Click here for more details.

Files changed (671) hide show
  1. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/PKG-INFO +1 -1
  2. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/_version.py +2 -2
  3. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/client/adapter.py +22 -3
  4. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/definitions.py +17 -1
  5. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/evaluation_handlers.py +193 -0
  6. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/types.py +105 -0
  7. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/client/test_adapter.py +17 -0
  8. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/client/test_adapter_transport_lifecycle.py +29 -15
  9. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/test_types.py +208 -2
  10. ouroboros_ai-0.28.8.dev9/tests/unit/mcp/tools/test_checklist_verify.py +341 -0
  11. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_definitions.py +5 -2
  12. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_evaluate_multi_ac.py +39 -0
  13. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.claude/settings.json +0 -0
  14. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.claude-plugin/.mcp.json +0 -0
  15. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.claude-plugin/marketplace.json +0 -0
  16. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.claude-plugin/plugin.json +0 -0
  17. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.env.example +0 -0
  18. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  19. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  21. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  22. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/workflows/dev-publish.yml +0 -0
  23. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/workflows/lint.yml +0 -0
  24. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/workflows/release.yml +0 -0
  25. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.github/workflows/test.yml +0 -0
  26. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.gitignore +0 -0
  27. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.mcp.json +0 -0
  28. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.ouroboros/mechanical.toml +0 -0
  29. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.ouroboros/seeds/seed_73827177a2a3.yaml +0 -0
  30. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.ouroboros/seeds/seed_78c8e6e41813.yaml +0 -0
  31. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.pre-commit-config.yaml +0 -0
  32. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/.python-version +0 -0
  33. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/CHANGELOG.md +0 -0
  34. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/CLAUDE.md +0 -0
  35. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/CODE_OF_CONDUCT.md +0 -0
  36. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/CONTRIBUTING.md +0 -0
  37. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/HANDOFF.md +0 -0
  38. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/LICENSE +0 -0
  39. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/README.ko.md +0 -0
  40. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/README.md +0 -0
  41. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/SECURITY.md +0 -0
  42. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/UNINSTALL.md +0 -0
  43. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/cancel.md +0 -0
  44. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/evaluate.md +0 -0
  45. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/evolve.md +0 -0
  46. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/help.md +0 -0
  47. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/interview.md +0 -0
  48. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/ralph.md +0 -0
  49. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/run.md +0 -0
  50. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/seed.md +0 -0
  51. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/setup.md +0 -0
  52. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/status.md +0 -0
  53. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/tutorial.md +0 -0
  54. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/unstuck.md +0 -0
  55. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/commands/welcome.md +0 -0
  56. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/.gitignore +0 -0
  57. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/Cargo.lock +0 -0
  58. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/Cargo.toml +0 -0
  59. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/README.md +0 -0
  60. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/db.rs +0 -0
  61. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/main.rs +0 -0
  62. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/mock.rs +0 -0
  63. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/state.rs +0 -0
  64. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/views/dashboard.rs +0 -0
  65. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/views/execution.rs +0 -0
  66. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/views/lineage.rs +0 -0
  67. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/views/logs.rs +0 -0
  68. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/views/mod.rs +0 -0
  69. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/crates/ouroboros-tui/src/views/session_selector.rs +0 -0
  70. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/README.md +0 -0
  71. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/api/README.md +0 -0
  72. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/api/core.md +0 -0
  73. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/api/mcp.md +0 -0
  74. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/architecture.md +0 -0
  75. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/assets/openclaw-ooo.png +0 -0
  76. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/cli-reference.md +0 -0
  77. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/config-reference.md +0 -0
  78. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/contributing/architecture-overview.md +0 -0
  79. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/contributing/findings-registry.md +0 -0
  80. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/contributing/issue-quality-policy.md +0 -0
  81. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/contributing/key-patterns.md +0 -0
  82. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/contributing/openclaw-current-baseline.md +0 -0
  83. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/contributing/testing-guide.md +0 -0
  84. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/events.md +0 -0
  85. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/examples/mcp-config.yaml +0 -0
  86. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/getting-started.md +0 -0
  87. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/guides/evaluation-pipeline.md +0 -0
  88. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/guides/evolution-loop.md +0 -0
  89. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/guides/issue-176-subagent-mcp-inheritance.md +0 -0
  90. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/guides/mcp-bridge.md +0 -0
  91. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/guides/openclaw-channel-workflow.md +0 -0
  92. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/guides/seed-authoring.md +0 -0
  93. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/guides/tui-usage.md +0 -0
  94. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/images/PLACEHOLDER_README.md +0 -0
  95. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/images/ouroboros.png +0 -0
  96. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/platform-support.md +0 -0
  97. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/runtime-capability-matrix.md +0 -0
  98. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/runtime-guides/claude-code.md +0 -0
  99. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/runtime-guides/codex.md +0 -0
  100. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/docs/runtime-guides/opencode.md +0 -0
  101. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/coordinator_test_seed.yaml +0 -0
  102. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/dummy_seed.yaml +0 -0
  103. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/parallel_subac_test_seed.yaml +0 -0
  104. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/subac_test_seed.yaml +0 -0
  105. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/task_manager/README.md +0 -0
  106. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/task_manager/__init__.py +0 -0
  107. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/task_manager/__main__.py +0 -0
  108. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/task_manager/cli.py +0 -0
  109. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/task_manager/models.py +0 -0
  110. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/task_manager/storage.py +0 -0
  111. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/examples/test_display.py +0 -0
  112. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/hooks/hooks.json +0 -0
  113. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/llms-full.txt +0 -0
  114. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/llms.txt +0 -0
  115. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/project-context.md +0 -0
  116. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/pyproject.toml +0 -0
  117. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/drift-monitor.py +0 -0
  118. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/install.sh +0 -0
  119. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/keyword-detector.py +0 -0
  120. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/mcp-serve.sh +0 -0
  121. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/ralph-rewind.py +0 -0
  122. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/ralph.py +0 -0
  123. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/ralph.sh +0 -0
  124. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/session-start.py +0 -0
  125. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/sync-plugin-version.py +0 -0
  126. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/scripts/version-check.py +0 -0
  127. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/brownfield/SKILL.md +0 -0
  128. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/cancel/SKILL.md +0 -0
  129. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/evaluate/SKILL.md +0 -0
  130. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/evolve/SKILL.md +0 -0
  131. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/help/SKILL.md +0 -0
  132. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/interview/SKILL.md +0 -0
  133. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/openclaw/SKILL.md +0 -0
  134. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/pm/SKILL.md +0 -0
  135. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/publish/SKILL.md +0 -0
  136. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/qa/SKILL.md +0 -0
  137. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/ralph/SKILL.md +0 -0
  138. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/run/SKILL.md +0 -0
  139. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/seed/SKILL.md +0 -0
  140. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/setup/SKILL.md +0 -0
  141. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/status/SKILL.md +0 -0
  142. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/tutorial/SKILL.md +0 -0
  143. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/unstuck/SKILL.md +0 -0
  144. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/update/SKILL.md +0 -0
  145. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/skills/welcome/SKILL.md +0 -0
  146. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/__init__.py +0 -0
  147. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/__main__.py +0 -0
  148. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/__init__.py +0 -0
  149. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/advocate.md +0 -0
  150. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/analysis-agent.md +0 -0
  151. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/architect.md +0 -0
  152. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/breadth-keeper.md +0 -0
  153. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/code-executor.md +0 -0
  154. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/codebase-explorer.md +0 -0
  155. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/consensus-reviewer.md +0 -0
  156. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/contrarian.md +0 -0
  157. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/evaluator.md +0 -0
  158. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/hacker.md +0 -0
  159. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/judge.md +0 -0
  160. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/loader.py +0 -0
  161. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/ontologist.md +0 -0
  162. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/ontology-analyst.md +0 -0
  163. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/qa-judge.md +0 -0
  164. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/research-agent.md +0 -0
  165. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/researcher.md +0 -0
  166. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/seed-architect.md +0 -0
  167. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/seed-closer.md +0 -0
  168. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/semantic-evaluator.md +0 -0
  169. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/simplifier.md +0 -0
  170. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/agents/socratic-interviewer.md +0 -0
  171. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/__init__.py +0 -0
  172. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/ambiguity.py +0 -0
  173. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/brownfield.py +0 -0
  174. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/explore.py +0 -0
  175. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/interview.py +0 -0
  176. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/pm_completion.py +0 -0
  177. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/pm_document.py +0 -0
  178. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/pm_interview.py +0 -0
  179. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/pm_seed.py +0 -0
  180. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/question_classifier.py +0 -0
  181. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/bigbang/seed_generator.py +0 -0
  182. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/__init__.py +0 -0
  183. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/__init__.py +0 -0
  184. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/cancel.py +0 -0
  185. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/config.py +0 -0
  186. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/init.py +0 -0
  187. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/mcp.py +0 -0
  188. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/pm.py +0 -0
  189. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/run.py +0 -0
  190. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/setup.py +0 -0
  191. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/status.py +0 -0
  192. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/tui.py +0 -0
  193. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/commands/uninstall.py +0 -0
  194. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/formatters/__init__.py +0 -0
  195. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/formatters/panels.py +0 -0
  196. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/formatters/progress.py +0 -0
  197. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/formatters/prompting.py +0 -0
  198. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/formatters/tables.py +0 -0
  199. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/formatters/workflow_display.py +0 -0
  200. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/jsonc.py +0 -0
  201. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/main.py +0 -0
  202. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/cli/opencode_config.py +0 -0
  203. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/codex/__init__.py +0 -0
  204. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/codex/artifacts.py +0 -0
  205. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/codex/cli_policy.py +0 -0
  206. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/codex/ouroboros.md +0 -0
  207. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/codex_permissions.py +0 -0
  208. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/config/__init__.py +0 -0
  209. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/config/loader.py +0 -0
  210. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/config/models.py +0 -0
  211. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/__init__.py +0 -0
  212. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/ac_tree.py +0 -0
  213. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/context.py +0 -0
  214. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/errors.py +0 -0
  215. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/file_lock.py +0 -0
  216. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/git_workflow.py +0 -0
  217. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/initial_context.py +0 -0
  218. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/json_utils.py +0 -0
  219. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/lineage.py +0 -0
  220. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/ontology_aspect.py +0 -0
  221. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/ontology_questions.py +0 -0
  222. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/project_paths.py +0 -0
  223. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/retry.py +0 -0
  224. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/security.py +0 -0
  225. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/seed.py +0 -0
  226. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/text.py +0 -0
  227. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/ttl_cache.py +0 -0
  228. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/types.py +0 -0
  229. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/core/worktree.py +0 -0
  230. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/__init__.py +0 -0
  231. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/artifact_collector.py +0 -0
  232. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/checklist.py +0 -0
  233. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/consensus.py +0 -0
  234. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/json_utils.py +0 -0
  235. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/languages.py +0 -0
  236. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/mechanical.py +0 -0
  237. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/models.py +0 -0
  238. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/pipeline.py +0 -0
  239. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/semantic.py +0 -0
  240. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/trigger.py +0 -0
  241. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evaluation/verification_artifacts.py +0 -0
  242. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/events/__init__.py +0 -0
  243. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/events/base.py +0 -0
  244. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/events/decomposition.py +0 -0
  245. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/events/evaluation.py +0 -0
  246. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/events/interview.py +0 -0
  247. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/events/lineage.py +0 -0
  248. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/events/ontology.py +0 -0
  249. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evolution/__init__.py +0 -0
  250. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evolution/convergence.py +0 -0
  251. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evolution/loop.py +0 -0
  252. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evolution/projector.py +0 -0
  253. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evolution/reflect.py +0 -0
  254. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evolution/regression.py +0 -0
  255. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/evolution/wonder.py +0 -0
  256. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/execution/__init__.py +0 -0
  257. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/execution/atomicity.py +0 -0
  258. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/execution/decomposition.py +0 -0
  259. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/execution/double_diamond.py +0 -0
  260. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/execution/subagent.py +0 -0
  261. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/__init__.py +0 -0
  262. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/bridge/__init__.py +0 -0
  263. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/bridge/bridge.py +0 -0
  264. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/bridge/config.py +0 -0
  265. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/bridge/factory.py +0 -0
  266. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/client/__init__.py +0 -0
  267. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/client/manager.py +0 -0
  268. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/client/protocol.py +0 -0
  269. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/errors.py +0 -0
  270. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/job_manager.py +0 -0
  271. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/resources/__init__.py +0 -0
  272. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/resources/handlers.py +0 -0
  273. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/server/__init__.py +0 -0
  274. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/server/adapter.py +0 -0
  275. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/server/protocol.py +0 -0
  276. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/server/security.py +0 -0
  277. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/__init__.py +0 -0
  278. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/ac_tree_hud_handler.py +0 -0
  279. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/ac_tree_hud_render.py +0 -0
  280. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/authoring_handlers.py +0 -0
  281. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/bridge_mixin.py +0 -0
  282. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/brownfield_handler.py +0 -0
  283. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/channel_workflow_handler.py +0 -0
  284. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/dashboard.py +0 -0
  285. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/evolution_handlers.py +0 -0
  286. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/execution_handlers.py +0 -0
  287. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/job_handlers.py +0 -0
  288. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/pm_handler.py +0 -0
  289. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/qa.py +0 -0
  290. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/query_handlers.py +0 -0
  291. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/mcp/tools/registry.py +0 -0
  292. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/observability/__init__.py +0 -0
  293. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/observability/drift.py +0 -0
  294. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/observability/logging.py +0 -0
  295. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/observability/retrospective.py +0 -0
  296. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/openclaw/__init__.py +0 -0
  297. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/openclaw/responses.py +0 -0
  298. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/openclaw/runtime.py +0 -0
  299. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/openclaw/store.py +0 -0
  300. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/openclaw/workflow.py +0 -0
  301. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/__init__.py +0 -0
  302. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/adapter.py +0 -0
  303. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/capabilities.py +0 -0
  304. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/codex_cli_runtime.py +0 -0
  305. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/command_dispatcher.py +0 -0
  306. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/control_plane.py +0 -0
  307. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/coordinator.py +0 -0
  308. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/dependency_analyzer.py +0 -0
  309. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/events.py +0 -0
  310. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/execution_runtime_scope.py +0 -0
  311. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/execution_strategy.py +0 -0
  312. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/heartbeat.py +0 -0
  313. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/level_context.py +0 -0
  314. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/mcp_config.py +0 -0
  315. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/mcp_tools.py +0 -0
  316. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/opencode_event_normalizer.py +0 -0
  317. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/opencode_runtime.py +0 -0
  318. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/parallel_executor.py +0 -0
  319. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/parallel_executor_models.py +0 -0
  320. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/policy.py +0 -0
  321. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/rate_limit.py +0 -0
  322. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/runner.py +0 -0
  323. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/runtime_factory.py +0 -0
  324. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/runtime_message_projection.py +0 -0
  325. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/session.py +0 -0
  326. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/orchestrator/workflow_state.py +0 -0
  327. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/__init__.py +0 -0
  328. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/brownfield.py +0 -0
  329. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/checkpoint.py +0 -0
  330. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/event_store.py +0 -0
  331. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/migrations/__init__.py +0 -0
  332. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/migrations/runner.py +0 -0
  333. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/migrations/scripts/001_initial.sql +0 -0
  334. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/migrations/scripts/002_brownfield.sql +0 -0
  335. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/schema.py +0 -0
  336. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/persistence/uow.py +0 -0
  337. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/__init__.py +0 -0
  338. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/agents/__init__.py +0 -0
  339. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/agents/pool.py +0 -0
  340. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/agents/registry.py +0 -0
  341. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/orchestration/__init__.py +0 -0
  342. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/orchestration/router.py +0 -0
  343. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/orchestration/scheduler.py +0 -0
  344. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/skills/__init__.py +0 -0
  345. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/skills/docs.py +0 -0
  346. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/skills/executor.py +0 -0
  347. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/skills/keywords.py +0 -0
  348. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/plugin/skills/registry.py +0 -0
  349. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/pm/__init__.py +0 -0
  350. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/pm/handoff.py +0 -0
  351. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/pm/renderer.py +0 -0
  352. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/__init__.py +0 -0
  353. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/anthropic_adapter.py +0 -0
  354. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/base.py +0 -0
  355. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/claude_code_adapter.py +0 -0
  356. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/codex_cli_adapter.py +0 -0
  357. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/codex_cli_stream.py +0 -0
  358. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/factory.py +0 -0
  359. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/gemini_cli_adapter.py +0 -0
  360. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/litellm_adapter.py +0 -0
  361. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/providers/opencode_adapter.py +0 -0
  362. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/py.typed +0 -0
  363. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/resilience/__init__.py +0 -0
  364. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/resilience/lateral.py +0 -0
  365. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/resilience/stagnation.py +0 -0
  366. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/routing/__init__.py +0 -0
  367. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/routing/complexity.py +0 -0
  368. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/routing/downgrade.py +0 -0
  369. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/routing/escalation.py +0 -0
  370. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/routing/router.py +0 -0
  371. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/routing/tiers.py +0 -0
  372. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/secondary/__init__.py +0 -0
  373. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/secondary/scheduler.py +0 -0
  374. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/secondary/todo_registry.py +0 -0
  375. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/strategies/__init__.py +0 -0
  376. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/strategies/devil_advocate.py +0 -0
  377. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/__init__.py +0 -0
  378. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/app.py +0 -0
  379. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/components/__init__.py +0 -0
  380. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/components/agents_panel.py +0 -0
  381. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/components/event_log.py +0 -0
  382. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/components/progress.py +0 -0
  383. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/components/token_tracker.py +0 -0
  384. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/events.py +0 -0
  385. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/__init__.py +0 -0
  386. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/confirm_rewind.py +0 -0
  387. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/dashboard.py +0 -0
  388. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/dashboard_v2.py +0 -0
  389. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/dashboard_v3.py +0 -0
  390. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/debug.py +0 -0
  391. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/execution.py +0 -0
  392. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/hud_dashboard.py +0 -0
  393. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/lineage_detail.py +0 -0
  394. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/lineage_selector.py +0 -0
  395. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/logs.py +0 -0
  396. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/screens/session_selector.py +0 -0
  397. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/__init__.py +0 -0
  398. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/ac_progress.py +0 -0
  399. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/ac_tree.py +0 -0
  400. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/agent_activity.py +0 -0
  401. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/cost_tracker.py +0 -0
  402. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/drift_meter.py +0 -0
  403. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/lineage_tree.py +0 -0
  404. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/parallel_graph.py +0 -0
  405. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/tui/widgets/phase_progress.py +0 -0
  406. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/verification/__init__.py +0 -0
  407. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/verification/extractor.py +0 -0
  408. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/verification/models.py +0 -0
  409. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/src/ouroboros/verification/verifier.py +0 -0
  410. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/__init__.py +0 -0
  411. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/conftest.py +0 -0
  412. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/e2e/__init__.py +0 -0
  413. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/e2e/conftest.py +0 -0
  414. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/e2e/mcp_bridge_test_config.yaml +0 -0
  415. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/e2e/test_cli_commands.py +0 -0
  416. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/e2e/test_full_workflow.py +0 -0
  417. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/e2e/test_session_persistence.py +0 -0
  418. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/fixtures/test_atomicity_seed.yml +0 -0
  419. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/__init__.py +0 -0
  420. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/conftest.py +0 -0
  421. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/mcp/__init__.py +0 -0
  422. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/mcp/bridge/__init__.py +0 -0
  423. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/mcp/bridge/test_bridge_server_to_server.py +0 -0
  424. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/mcp/conftest.py +0 -0
  425. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/mcp/test_client_adapter.py +0 -0
  426. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/mcp/test_client_manager.py +0 -0
  427. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/mcp/test_server_adapter.py +0 -0
  428. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/plugin/test_orchestration.py +0 -0
  429. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/test_codex_cli_passthrough_smoke.py +0 -0
  430. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/test_codex_skill_fallback.py +0 -0
  431. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/test_codex_skill_smoke.py +0 -0
  432. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/integration/test_entry_point.py +0 -0
  433. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/__init__.py +0 -0
  434. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/agents/__init__.py +0 -0
  435. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/agents/test_loader.py +0 -0
  436. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/__init__.py +0 -0
  437. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_ambiguity.py +0 -0
  438. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_brownfield.py +0 -0
  439. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_classifier_context.py +0 -0
  440. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_decide_later_items.py +0 -0
  441. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_explore.py +0 -0
  442. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_interview.py +0 -0
  443. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_interview_async_io.py +0 -0
  444. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_interview_no_web_search_hint.py +0 -0
  445. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_interview_research_prefix.py +0 -0
  446. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_pm_completion.py +0 -0
  447. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_pm_document_generator.py +0 -0
  448. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_pm_document_writer.py +0 -0
  449. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_pm_interview.py +0 -0
  450. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_pm_interview_brownfield_db.py +0 -0
  451. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_pm_seed_ac12.py +0 -0
  452. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_pm_seed_save.py +0 -0
  453. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_question_classifier.py +0 -0
  454. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/bigbang/test_seed_generator.py +0 -0
  455. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/__init__.py +0 -0
  456. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/commands/test_tui_command.py +0 -0
  457. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/formatters/__init__.py +0 -0
  458. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/formatters/test_console.py +0 -0
  459. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/formatters/test_panels.py +0 -0
  460. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/formatters/test_progress.py +0 -0
  461. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/formatters/test_prompting.py +0 -0
  462. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/formatters/test_tables.py +0 -0
  463. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/formatters/test_workflow_display.py +0 -0
  464. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_cancel.py +0 -0
  465. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_config.py +0 -0
  466. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_init_pm_seed_detection.py +0 -0
  467. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_init_runtime.py +0 -0
  468. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_jsonc.py +0 -0
  469. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_main.py +0 -0
  470. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_mcp_nested_guard.py +0 -0
  471. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_mcp_startup_cleanup.py +0 -0
  472. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_mcp_validate_transport_stderr.py +0 -0
  473. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_opencode_config.py +0 -0
  474. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm.py +0 -0
  475. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm_brownfield.py +0 -0
  476. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm_completion.py +0 -0
  477. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm_interactive_logging.py +0 -0
  478. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm_missing_litellm.py +0 -0
  479. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm_overwrite.py +0 -0
  480. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm_runtime_adapter.py +0 -0
  481. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_pm_select_repos.py +0 -0
  482. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_run_qa.py +0 -0
  483. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_setup.py +0 -0
  484. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/cli/test_uninstall.py +0 -0
  485. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/codex/test_cli_policy.py +0 -0
  486. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/config/__init__.py +0 -0
  487. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/config/test_loader.py +0 -0
  488. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/config/test_loader_env.py +0 -0
  489. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/config/test_models.py +0 -0
  490. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/__init__.py +0 -0
  491. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_ac_tree.py +0 -0
  492. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_context.py +0 -0
  493. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_errors.py +0 -0
  494. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_file_lock.py +0 -0
  495. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_git_workflow.py +0 -0
  496. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_initial_context.py +0 -0
  497. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_lineage.py +0 -0
  498. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_ontology_aspect.py +0 -0
  499. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_ontology_questions.py +0 -0
  500. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_retry.py +0 -0
  501. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_security.py +0 -0
  502. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_seed.py +0 -0
  503. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_ttl_cache.py +0 -0
  504. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_types.py +0 -0
  505. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/core/test_worktree.py +0 -0
  506. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/__init__.py +0 -0
  507. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_artifact_collector_file_prefix.py +0 -0
  508. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_checklist.py +0 -0
  509. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_consensus.py +0 -0
  510. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_json_utils.py +0 -0
  511. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_languages.py +0 -0
  512. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_mechanical.py +0 -0
  513. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_models.py +0 -0
  514. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_pipeline_trigger_consensus.py +0 -0
  515. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_review_fixes.py +0 -0
  516. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_semantic.py +0 -0
  517. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_trigger.py +0 -0
  518. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_trigger_consensus.py +0 -0
  519. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evaluation/test_verification_artifacts.py +0 -0
  520. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/events/__init__.py +0 -0
  521. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/events/test_base.py +0 -0
  522. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/events/test_decomposition_events.py +0 -0
  523. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/evolution/test_wonder_scope.py +0 -0
  524. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/execution/__init__.py +0 -0
  525. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/execution/test_atomicity.py +0 -0
  526. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/execution/test_decomposition.py +0 -0
  527. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/execution/test_double_diamond.py +0 -0
  528. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/execution/test_subagent_isolation.py +0 -0
  529. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/__init__.py +0 -0
  530. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/bridge/__init__.py +0 -0
  531. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/bridge/test_bridge.py +0 -0
  532. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/bridge/test_config.py +0 -0
  533. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/bridge/test_factory.py +0 -0
  534. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/bridge/test_handler_wiring.py +0 -0
  535. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/bridge/test_stability.py +0 -0
  536. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/client/__init__.py +0 -0
  537. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/client/test_manager.py +0 -0
  538. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/conftest.py +0 -0
  539. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/server/__init__.py +0 -0
  540. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/server/test_adapter.py +0 -0
  541. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/server/test_security.py +0 -0
  542. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/test_errors.py +0 -0
  543. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/test_job_manager.py +0 -0
  544. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/__init__.py +0 -0
  545. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/conftest.py +0 -0
  546. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_footer.py +0 -0
  547. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_handler.py +0 -0
  548. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_handler_completed.py +0 -0
  549. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_handler_cursor_changed.py +0 -0
  550. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_handler_invalid_session.py +0 -0
  551. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_handler_no_execution.py +0 -0
  552. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_handler_waiting.py +0 -0
  553. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_max_nodes.py +0 -0
  554. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_render_depth2.py +0 -0
  555. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_render_depth3.py +0 -0
  556. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_status_icons.py +0 -0
  557. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_ac_tree_hud_truncation.py +0 -0
  558. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_brownfield_handler.py +0 -0
  559. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_channel_workflow_handler.py +0 -0
  560. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_evaluation_handler.py +0 -0
  561. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_interview_parallel_scoring.py +0 -0
  562. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_interview_scoring_flow.py +0 -0
  563. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_interview_scoring_guard.py +0 -0
  564. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_mcp_manager_wiring.py +0 -0
  565. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_pm_handler.py +0 -0
  566. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_pm_handler_generate.py +0 -0
  567. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_pm_handler_pending_reframe.py +0 -0
  568. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_qa_integration.py +0 -0
  569. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_qa_parser.py +0 -0
  570. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_registry.py +0 -0
  571. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/mcp/tools/test_traceback_reporting.py +0 -0
  572. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/observability/__init__.py +0 -0
  573. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/observability/test_drift.py +0 -0
  574. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/observability/test_logging.py +0 -0
  575. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/observability/test_retrospective.py +0 -0
  576. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/openclaw/test_workflow.py +0 -0
  577. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/__init__.py +0 -0
  578. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_adapter.py +0 -0
  579. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_capabilities.py +0 -0
  580. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_codex_cli_runtime.py +0 -0
  581. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_codex_recursion_guard.py +0 -0
  582. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_command_dispatcher.py +0 -0
  583. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_control_plane.py +0 -0
  584. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_coordinator.py +0 -0
  585. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_dependency_analyzer.py +0 -0
  586. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_events.py +0 -0
  587. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_execution_runtime_scope.py +0 -0
  588. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_execution_strategy.py +0 -0
  589. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_inflight_cancellation.py +0 -0
  590. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_level_context.py +0 -0
  591. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_mcp_config.py +0 -0
  592. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_mcp_tools.py +0 -0
  593. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_opencode_runtime.py +0 -0
  594. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_parallel_executor.py +0 -0
  595. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_parallel_executor_atomic_judgment.py +0 -0
  596. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_parallel_executor_recursive_depth.py +0 -0
  597. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_parallel_executor_retry_resume.py +0 -0
  598. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_policy.py +0 -0
  599. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_rate_limit.py +0 -0
  600. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_runner.py +0 -0
  601. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_runner_cancellation.py +0 -0
  602. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_runtime_factory.py +0 -0
  603. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_runtime_message_projection.py +0 -0
  604. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_session.py +0 -0
  605. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/orchestrator/test_workflow_state.py +0 -0
  606. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/persistence/__init__.py +0 -0
  607. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/persistence/test_brownfield_store.py +0 -0
  608. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/persistence/test_checkpoint.py +0 -0
  609. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/persistence/test_event_store.py +0 -0
  610. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/persistence/test_schema.py +0 -0
  611. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/persistence/test_uow.py +0 -0
  612. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/__init__.py +0 -0
  613. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/agents/__init__.py +0 -0
  614. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/agents/test_registry.py +0 -0
  615. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/orchestration/__init__.py +0 -0
  616. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/orchestration/test_model_router.py +0 -0
  617. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/skills/__init__.py +0 -0
  618. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/skills/test_keywords.py +0 -0
  619. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/plugin/skills/test_registry.py +0 -0
  620. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/pm/__init__.py +0 -0
  621. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/pm/test_renderer.py +0 -0
  622. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/__init__.py +0 -0
  623. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/test_base.py +0 -0
  624. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/test_claude_code_adapter.py +0 -0
  625. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/test_codex_cli_adapter.py +0 -0
  626. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/test_factory.py +0 -0
  627. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/test_gemini_cli_adapter.py +0 -0
  628. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/test_litellm_adapter.py +0 -0
  629. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/providers/test_opencode_adapter.py +0 -0
  630. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/resilience/__init__.py +0 -0
  631. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/resilience/test_lateral.py +0 -0
  632. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/resilience/test_stagnation.py +0 -0
  633. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/routing/__init__.py +0 -0
  634. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/routing/test_complexity.py +0 -0
  635. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/routing/test_downgrade.py +0 -0
  636. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/routing/test_escalation.py +0 -0
  637. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/routing/test_router.py +0 -0
  638. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/routing/test_tiers.py +0 -0
  639. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/scripts/test_keyword_detector.py +0 -0
  640. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/scripts/test_session_start.py +0 -0
  641. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/scripts/test_version_check.py +0 -0
  642. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/secondary/__init__.py +0 -0
  643. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/secondary/test_scheduler.py +0 -0
  644. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/secondary/test_todo_registry.py +0 -0
  645. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_artifact_collector.py +0 -0
  646. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_codex_artifacts.py +0 -0
  647. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_convergence.py +0 -0
  648. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_dashboard.py +0 -0
  649. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_dependencies_configured.py +0 -0
  650. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_evolve_rewind.py +0 -0
  651. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_evolve_step.py +0 -0
  652. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_graceful_shutdown.py +0 -0
  653. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_main_entry_point.py +0 -0
  654. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_module_structure.py +0 -0
  655. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_project_initialization.py +0 -0
  656. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_projector_rewind.py +0 -0
  657. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_ralph_parser.py +0 -0
  658. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_ralph_rewind.py +0 -0
  659. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_regression.py +0 -0
  660. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_tooling_configuration.py +0 -0
  661. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/test_verification.py +0 -0
  662. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/__init__.py +0 -0
  663. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/test_app.py +0 -0
  664. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/test_cancelled_display.py +0 -0
  665. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/test_events.py +0 -0
  666. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/test_lineage_viewer.py +0 -0
  667. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/test_screens.py +0 -0
  668. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/test_session_selector_replay.py +0 -0
  669. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tests/unit/tui/test_widgets.py +0 -0
  670. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/tools/sync_github_project.py +0 -0
  671. {ouroboros_ai-0.28.8.dev4 → ouroboros_ai-0.28.8.dev9}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ouroboros-ai
3
- Version: 0.28.8.dev4
3
+ Version: 0.28.8.dev9
4
4
  Summary: Specification-first workflow engine for AI coding agents. Works with Claude Code and Codex CLI.
5
5
  Author-email: Q00 <jqyu.lee@gmail.com>
6
6
  License-File: LICENSE
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.28.8.dev4'
22
- __version_tuple__ = version_tuple = (0, 28, 8, 'dev4')
21
+ __version__ = version = '0.28.8.dev9'
22
+ __version_tuple__ = version_tuple = (0, 28, 8, 'dev9')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -258,12 +258,31 @@ class MCPClientAdapter:
258
258
 
259
259
  import httpx
260
260
  from mcp.client.streamable_http import streamable_http_client
261
- from mcp.shared._httpx_utils import create_mcp_http_client
261
+
262
+ from ouroboros import __version__ as _ouroboros_version
262
263
 
263
264
  timeout = httpx.Timeout(config.timeout, read=max(config.timeout, 300.0))
264
- http_client = create_mcp_http_client(
265
- headers=config.headers if config.headers else None,
265
+
266
+ # Compose headers with a stable User-Agent for observability.
267
+ # Now that we own the httpx client (no longer going through the
268
+ # mcp SDK's private helper), set the UA explicitly so that MCP
269
+ # servers can still identify the ouroboros client in their logs.
270
+ # Caller-supplied headers take precedence.
271
+ default_headers = {
272
+ "User-Agent": f"ouroboros-mcp-client/{_ouroboros_version}",
273
+ }
274
+ if config.headers:
275
+ merged_headers: dict[str, str] = {**default_headers, **config.headers}
276
+ else:
277
+ merged_headers = default_headers
278
+
279
+ http_client = httpx.AsyncClient(
280
+ headers=merged_headers,
266
281
  timeout=timeout,
282
+ # SSRF hardening: do not follow redirects. An attacker-controlled
283
+ # server could otherwise 302 us into a loopback / metadata URL
284
+ # that bypasses the static URL validation in MCPServerConfig.
285
+ follow_redirects=False,
267
286
  )
268
287
  self._http_client = http_client
269
288
 
@@ -26,6 +26,7 @@ from ouroboros.mcp.tools.authoring_handlers import (
26
26
  )
27
27
  from ouroboros.mcp.tools.channel_workflow_handler import ChannelWorkflowHandler
28
28
  from ouroboros.mcp.tools.evaluation_handlers import (
29
+ ChecklistVerifyHandler,
29
30
  EvaluateHandler,
30
31
  LateralThinkHandler,
31
32
  MeasureDriftHandler,
@@ -186,6 +187,18 @@ def evaluate_handler(*, llm_backend: str | None = None) -> EvaluateHandler:
186
187
  return EvaluateHandler(llm_backend=llm_backend)
187
188
 
188
189
 
190
+ def checklist_verify_handler(
191
+ *,
192
+ evaluate_handler: EvaluateHandler | None = None,
193
+ llm_backend: str | None = None,
194
+ ) -> ChecklistVerifyHandler:
195
+ """Create a ChecklistVerifyHandler instance."""
196
+ return ChecklistVerifyHandler(
197
+ evaluate_handler=evaluate_handler,
198
+ llm_backend=llm_backend,
199
+ )
200
+
201
+
189
202
  def evolve_step_handler() -> EvolveStepHandler:
190
203
  """Create an EvolveStepHandler instance."""
191
204
  return EvolveStepHandler()
@@ -226,6 +239,7 @@ OuroborosToolHandlers = tuple[
226
239
  | MeasureDriftHandler
227
240
  | InterviewHandler
228
241
  | EvaluateHandler
242
+ | ChecklistVerifyHandler
229
243
  | LateralThinkHandler
230
244
  | EvolveStepHandler
231
245
  | StartEvolveStepHandler
@@ -265,6 +279,7 @@ def get_ouroboros_tools(
265
279
  job_result = JobResultHandler()
266
280
  interview = InterviewHandler(llm_backend=llm_backend)
267
281
  generate_seed = GenerateSeedHandler(llm_backend=llm_backend)
282
+ evaluate = EvaluateHandler(llm_backend=llm_backend)
268
283
  return (
269
284
  execute_seed,
270
285
  start_execute,
@@ -278,7 +293,8 @@ def get_ouroboros_tools(
278
293
  generate_seed,
279
294
  MeasureDriftHandler(),
280
295
  interview,
281
- EvaluateHandler(llm_backend=llm_backend),
296
+ evaluate,
297
+ ChecklistVerifyHandler(evaluate_handler=evaluate, llm_backend=llm_backend),
282
298
  LateralThinkHandler(),
283
299
  EvolveStepHandler(),
284
300
  StartEvolveStepHandler(),
@@ -874,6 +874,199 @@ class EvaluateHandler:
874
874
  return "\n".join(lines)
875
875
 
876
876
 
877
+ @dataclass
878
+ class ChecklistVerifyHandler:
879
+ """Handler for the ``ouroboros_checklist_verify`` tool (#366).
880
+
881
+ Given a seed (containing ``acceptance_criteria``) and an execution
882
+ artifact, this handler routes each AC through the Stage 2 evaluation
883
+ pipeline and returns an aggregated checklist. It is intentionally
884
+ thin — it composes ``EvaluateHandler`` rather than reimplementing
885
+ pipeline orchestration, so it stays in sync with any future changes
886
+ to the main evaluator.
887
+
888
+ Why this is a separate tool instead of a flag on ``ouroboros_execute_seed``:
889
+
890
+ - ``ExecuteSeed`` is already complex (background execution, resume,
891
+ delegation) and has a stable public contract. Adding a retry
892
+ loop inside it would entangle with Ralph mode and the Job system.
893
+ - This tool lets the *caller* (a human, a ``/ralph`` loop, or a
894
+ channel workflow) decide when and how to retry. No decisions
895
+ are hidden inside background tasks.
896
+ - It is opt-in: existing callers are unaffected.
897
+ """
898
+
899
+ evaluate_handler: EvaluateHandler | None = field(default=None, repr=False)
900
+ llm_backend: str | None = field(default=None, repr=False)
901
+
902
+ @property
903
+ def definition(self) -> MCPToolDefinition:
904
+ """Return the tool definition."""
905
+ return MCPToolDefinition(
906
+ name="ouroboros_checklist_verify",
907
+ description=(
908
+ "Verify that a Run artifact satisfies every acceptance criterion "
909
+ "in a Seed. Returns a per-AC checklist (pass/fail with evidence "
910
+ "and failure reasons) plus ready-to-use run_feedback strings the "
911
+ "caller can inject into a re-run prompt. Does NOT automatically "
912
+ "re-execute — the caller (Ralph, workflow, or human) decides."
913
+ ),
914
+ parameters=(
915
+ MCPToolParameter(
916
+ name="session_id",
917
+ type=ToolInputType.STRING,
918
+ description="The execution session ID being verified",
919
+ required=True,
920
+ ),
921
+ MCPToolParameter(
922
+ name="seed_content",
923
+ type=ToolInputType.STRING,
924
+ description=(
925
+ "Seed YAML containing acceptance_criteria, goal, constraints. "
926
+ "The seed's acceptance_criteria list is evaluated in full."
927
+ ),
928
+ required=True,
929
+ ),
930
+ MCPToolParameter(
931
+ name="artifact",
932
+ type=ToolInputType.STRING,
933
+ description="The Run output/artifact to verify against the seed's ACs",
934
+ required=True,
935
+ ),
936
+ MCPToolParameter(
937
+ name="artifact_type",
938
+ type=ToolInputType.STRING,
939
+ description="Type of artifact: code, docs, config. Default: code",
940
+ required=False,
941
+ default="code",
942
+ enum=("code", "docs", "config"),
943
+ ),
944
+ MCPToolParameter(
945
+ name="working_dir",
946
+ type=ToolInputType.STRING,
947
+ description="Project working directory (for language auto-detection).",
948
+ required=False,
949
+ ),
950
+ ),
951
+ )
952
+
953
+ async def handle(
954
+ self,
955
+ arguments: dict[str, Any],
956
+ ) -> Result[MCPToolResult, MCPServerError]:
957
+ """Verify the seed's full AC list against the artifact."""
958
+ session_id = arguments.get("session_id")
959
+ if not session_id:
960
+ return Result.err(
961
+ MCPToolError(
962
+ "session_id is required",
963
+ tool_name="ouroboros_checklist_verify",
964
+ )
965
+ )
966
+
967
+ seed_content = arguments.get("seed_content")
968
+ if not seed_content:
969
+ return Result.err(
970
+ MCPToolError(
971
+ "seed_content is required",
972
+ tool_name="ouroboros_checklist_verify",
973
+ )
974
+ )
975
+
976
+ artifact = arguments.get("artifact")
977
+ if not artifact:
978
+ return Result.err(
979
+ MCPToolError(
980
+ "artifact is required",
981
+ tool_name="ouroboros_checklist_verify",
982
+ )
983
+ )
984
+
985
+ # Extract acceptance criteria from seed.
986
+ try:
987
+ seed_dict = yaml.safe_load(seed_content)
988
+ seed = Seed.from_dict(seed_dict)
989
+ except yaml.YAMLError as exc:
990
+ log.warning("mcp.tool.checklist_verify.yaml_error", error=str(exc))
991
+ return Result.err(
992
+ MCPToolError(
993
+ f"Failed to parse seed YAML: {exc}",
994
+ tool_name="ouroboros_checklist_verify",
995
+ )
996
+ )
997
+ except (ValidationError, PydanticValidationError) as exc:
998
+ log.warning("mcp.tool.checklist_verify.seed_validation_error", error=str(exc))
999
+ return Result.err(
1000
+ MCPToolError(
1001
+ f"Seed validation failed: {exc}",
1002
+ tool_name="ouroboros_checklist_verify",
1003
+ )
1004
+ )
1005
+
1006
+ acceptance_criteria = tuple(
1007
+ text.strip() for text in seed.acceptance_criteria if text and text.strip()
1008
+ )
1009
+ if not acceptance_criteria:
1010
+ return Result.err(
1011
+ MCPToolError(
1012
+ "Seed has no acceptance_criteria — cannot build checklist.",
1013
+ tool_name="ouroboros_checklist_verify",
1014
+ )
1015
+ )
1016
+
1017
+ # Delegate to EvaluateHandler in multi-AC mode. Re-using the
1018
+ # evaluator means language detection, artifact bundling, event
1019
+ # logging, and LLM backend handling stay consistent.
1020
+ evaluator = self.evaluate_handler or EvaluateHandler(llm_backend=self.llm_backend)
1021
+
1022
+ evaluate_args = {
1023
+ "session_id": session_id,
1024
+ "artifact": artifact,
1025
+ "seed_content": seed_content,
1026
+ "acceptance_criteria": list(acceptance_criteria),
1027
+ "artifact_type": arguments.get("artifact_type", "code"),
1028
+ }
1029
+ if "working_dir" in arguments:
1030
+ evaluate_args["working_dir"] = arguments["working_dir"]
1031
+
1032
+ log.info(
1033
+ "mcp.tool.checklist_verify.started",
1034
+ session_id=session_id,
1035
+ ac_count=len(acceptance_criteria),
1036
+ )
1037
+
1038
+ result = await evaluator.handle(evaluate_args)
1039
+
1040
+ if result.is_err:
1041
+ log.warning(
1042
+ "mcp.tool.checklist_verify.evaluate_failed",
1043
+ session_id=session_id,
1044
+ error=str(result.error),
1045
+ )
1046
+ return result
1047
+
1048
+ # Augment the MCP result meta so callers can distinguish the
1049
+ # verify path from a plain multi-AC evaluate call.
1050
+ meta = dict(result.value.meta or {})
1051
+ meta["checklist_verify"] = True
1052
+ meta["seed_goal"] = seed.goal
1053
+ augmented = MCPToolResult(
1054
+ content=result.value.content,
1055
+ is_error=result.value.is_error,
1056
+ meta=meta,
1057
+ )
1058
+
1059
+ log.info(
1060
+ "mcp.tool.checklist_verify.completed",
1061
+ session_id=session_id,
1062
+ all_passed=meta.get("final_approved"),
1063
+ passed_count=meta.get("passed_count"),
1064
+ ac_count=meta.get("ac_count"),
1065
+ )
1066
+
1067
+ return Result.ok(augmented)
1068
+
1069
+
877
1070
  @dataclass
878
1071
  class LateralThinkHandler:
879
1072
  """Handler for the lateral_think tool.
@@ -8,7 +8,110 @@ from __future__ import annotations
8
8
 
9
9
  from dataclasses import dataclass, field
10
10
  from enum import StrEnum
11
+ import ipaddress
12
+ import os
11
13
  from typing import Any
14
+ from urllib.parse import urlparse
15
+
16
+ # Schemes permitted for SSE / HTTP / STREAMABLE_HTTP transports.
17
+ _ALLOWED_URL_SCHEMES = frozenset({"http", "https"})
18
+
19
+ # Environment flag that intentionally re-enables loopback / private / link-local
20
+ # IP literals for local development. Leave unset in production.
21
+ _ALLOW_LOCAL_TRANSPORT_ENV = "OUROBOROS_ALLOW_LOCAL_TRANSPORT"
22
+
23
+ # Well-known hostnames that resolve to loopback addresses. These bypass the
24
+ # ``ipaddress.ip_address()`` check (they raise ``ValueError`` because they are
25
+ # not IP literals), so we must block them explicitly.
26
+ _LOOPBACK_HOSTNAMES = frozenset({"localhost"})
27
+
28
+
29
+ def _validate_transport_url(url: str, transport: str) -> None:
30
+ """Validate a transport URL against common SSRF vectors.
31
+
32
+ The MCP client will dial whatever URL is configured for SSE, HTTP, or
33
+ STREAMABLE_HTTP transports. Without hardening, that turns any untrusted
34
+ caller that can influence the ``url`` field into an SSRF primitive able to
35
+ reach cloud metadata services (169.254.169.254), loopback services, or
36
+ private RFC1918 ranges. This helper rejects the common vectors before a
37
+ connection is attempted.
38
+
39
+ Blocks:
40
+ * Non-http(s) schemes (``file://``, ``gopher://``, ``ftp://`` ...).
41
+ * URLs carrying userinfo (``user:pass@host``) used for credential
42
+ smuggling / host confusion.
43
+ * URLs with an empty hostname (e.g. bare ``http://``).
44
+ * Literal IPs resolving to loopback, link-local, or private ranges,
45
+ unless the ``OUROBOROS_ALLOW_LOCAL_TRANSPORT=1`` dev escape is set.
46
+
47
+ DNS resolution is intentionally out of scope for this static validation;
48
+ runtime code that follows redirects should be hardened separately (the
49
+ adapter sets ``follow_redirects=False``).
50
+
51
+ Args:
52
+ url: The transport URL to validate.
53
+ transport: Name of the transport (used only in error messages).
54
+
55
+ Raises:
56
+ ValueError: If any SSRF guard is triggered.
57
+ """
58
+
59
+ parsed = urlparse(url)
60
+ scheme = parsed.scheme.lower()
61
+
62
+ if scheme not in _ALLOWED_URL_SCHEMES:
63
+ msg = (
64
+ f"Only http:// and https:// URLs are supported for {transport} "
65
+ f"transport, got: {parsed.scheme}://"
66
+ )
67
+ raise ValueError(msg)
68
+
69
+ if parsed.username or parsed.password:
70
+ msg = "Transport URL must not contain userinfo (credentials)"
71
+ raise ValueError(msg)
72
+
73
+ hostname = parsed.hostname
74
+ if not hostname:
75
+ msg = "Transport URL must include a hostname"
76
+ raise ValueError(msg)
77
+
78
+ allow_local = os.environ.get(_ALLOW_LOCAL_TRANSPORT_ENV, "0") == "1"
79
+
80
+ # Strip IPv6 brackets (urlparse already does, but be defensive).
81
+ host_literal = hostname.strip("[]")
82
+
83
+ # Check for well-known loopback hostnames before attempting IP parsing.
84
+ # These bypass the IP-literal checks because they are DNS names, but
85
+ # they resolve to loopback addresses and must be blocked unless the
86
+ # dev escape hatch is enabled.
87
+ if host_literal in _LOOPBACK_HOSTNAMES:
88
+ if allow_local:
89
+ return
90
+ msg = (
91
+ f"Transport URL points to a local hostname: "
92
+ f"{hostname}. Set {_ALLOW_LOCAL_TRANSPORT_ENV}=1 for local dev."
93
+ )
94
+ raise ValueError(msg)
95
+
96
+ try:
97
+ ip = ipaddress.ip_address(host_literal)
98
+ except ValueError:
99
+ # Not an IP literal -- a DNS name. Static validation ends here.
100
+ return
101
+
102
+ if allow_local:
103
+ return
104
+
105
+ if ip.is_loopback or ip.is_link_local or ip.is_private or ip.is_multicast:
106
+ msg = (
107
+ f"Transport URL points to loopback/link-local/private IP: "
108
+ f"{hostname}. Set {_ALLOW_LOCAL_TRANSPORT_ENV}=1 for local dev."
109
+ )
110
+ raise ValueError(msg)
111
+
112
+ if ip.is_reserved or ip.is_unspecified:
113
+ msg = f"Transport URL points to reserved/unspecified IP: {hostname}"
114
+ raise ValueError(msg)
12
115
 
13
116
 
14
117
  class TransportType(StrEnum):
@@ -71,6 +174,8 @@ class MCPServerConfig:
71
174
  ):
72
175
  msg = f"url is required for {self.transport} transport"
73
176
  raise ValueError(msg)
177
+ if self.url:
178
+ _validate_transport_url(self.url, str(self.transport))
74
179
 
75
180
 
76
181
  @dataclass(frozen=True, slots=True)
@@ -1,5 +1,6 @@
1
1
  """Tests for MCP client adapter."""
2
2
 
3
+ import inspect
3
4
  from unittest.mock import AsyncMock, MagicMock
4
5
 
5
6
  from ouroboros.mcp.client.adapter import MCPClientAdapter
@@ -134,3 +135,19 @@ class TestMCPClientAdapterRetry:
134
135
  assert adapter._max_retries == 5
135
136
  assert adapter._retry_wait_initial == 2.0
136
137
  assert adapter._retry_wait_max == 20.0
138
+
139
+
140
+ class TestNoPrivateAPIImport:
141
+ """Verify private MCP SDK imports are not used."""
142
+
143
+ def test_no_private_httpx_utils_import(self) -> None:
144
+ """adapter.py must not import from mcp.shared._httpx_utils (private API)."""
145
+ import ouroboros.mcp.client.adapter as adapter_module
146
+
147
+ source = inspect.getsource(adapter_module)
148
+ assert "_httpx_utils" not in source, (
149
+ "adapter.py still references the private mcp.shared._httpx_utils module"
150
+ )
151
+ assert "create_mcp_http_client" not in source, (
152
+ "adapter.py still references the private create_mcp_http_client helper"
153
+ )
@@ -17,6 +17,12 @@ from ouroboros.mcp.client.adapter import MCPClientAdapter
17
17
  from ouroboros.mcp.types import MCPServerConfig, TransportType
18
18
 
19
19
 
20
+ @pytest.fixture(autouse=True)
21
+ def _allow_local_transport(monkeypatch: pytest.MonkeyPatch) -> None:
22
+ """These tests use localhost URLs — enable the local transport escape hatch."""
23
+ monkeypatch.setenv("OUROBOROS_ALLOW_LOCAL_TRANSPORT", "1")
24
+
25
+
20
26
  def _make_stdio_config(name: str = "test") -> MCPServerConfig:
21
27
  return MCPServerConfig(
22
28
  name=name,
@@ -311,7 +317,7 @@ class TestHTTPTransportConnect:
311
317
  with (
312
318
  patch("mcp.client.streamable_http.streamable_http_client", return_value=transport_cm),
313
319
  patch("mcp.ClientSession", return_value=session),
314
- patch("mcp.shared._httpx_utils.create_mcp_http_client"),
320
+ patch("httpx.AsyncClient"),
315
321
  ):
316
322
  result = await adapter.connect(_make_http_config())
317
323
 
@@ -329,7 +335,7 @@ class TestHTTPTransportConnect:
329
335
  with (
330
336
  patch("mcp.client.streamable_http.streamable_http_client", return_value=transport_cm),
331
337
  patch("mcp.ClientSession", return_value=session),
332
- patch("mcp.shared._httpx_utils.create_mcp_http_client"),
338
+ patch("httpx.AsyncClient"),
333
339
  ):
334
340
  result = await adapter.connect(
335
341
  _make_http_config(transport=TransportType.STREAMABLE_HTTP)
@@ -355,7 +361,7 @@ class TestHTTPTransportConnect:
355
361
  with (
356
362
  patch("mcp.client.streamable_http.streamable_http_client", return_value=transport_cm),
357
363
  patch("mcp.ClientSession", return_value=session),
358
- patch("mcp.shared._httpx_utils.create_mcp_http_client"),
364
+ patch("httpx.AsyncClient"),
359
365
  ):
360
366
  result = await adapter.connect(_make_http_config())
361
367
 
@@ -366,7 +372,7 @@ class TestHTTPTransportConnect:
366
372
 
367
373
  @pytest.mark.asyncio
368
374
  async def test_http_connect_passes_headers(self):
369
- """When config has headers, create_mcp_http_client called with them."""
375
+ """When config has headers, httpx.AsyncClient is called with them."""
370
376
  adapter = MCPClientAdapter()
371
377
  transport_cm = _mock_http_transport_cm()
372
378
  session = _mock_session()
@@ -383,17 +389,22 @@ class TestHTTPTransportConnect:
383
389
  "mcp.client.streamable_http.streamable_http_client", return_value=transport_cm
384
390
  ) as mock_http,
385
391
  patch("mcp.ClientSession", return_value=session),
386
- patch("mcp.shared._httpx_utils.create_mcp_http_client") as mock_factory,
392
+ patch("httpx.AsyncClient") as mock_async_client,
387
393
  ):
388
394
  result = await adapter.connect(config)
389
395
 
390
396
  assert result.is_ok
391
- mock_factory.assert_called_once()
392
- call_kwargs = mock_factory.call_args
393
- assert call_kwargs.kwargs["headers"] == {"Authorization": "Bearer token123"}
397
+ mock_async_client.assert_called_once()
398
+ call_kwargs = mock_async_client.call_args
399
+ # Caller-supplied headers must survive merging with the default UA.
400
+ headers = call_kwargs.kwargs["headers"]
401
+ assert headers["Authorization"] == "Bearer token123"
402
+ assert headers["User-Agent"].startswith("ouroboros-mcp-client/")
403
+ # SSRF hardening: redirects disabled on the transport httpx client.
404
+ assert call_kwargs.kwargs["follow_redirects"] is False
394
405
  mock_http.assert_called_once_with(
395
406
  "http://localhost:3000",
396
- http_client=mock_factory.return_value,
407
+ http_client=mock_async_client.return_value,
397
408
  )
398
409
 
399
410
  @pytest.mark.asyncio
@@ -413,7 +424,7 @@ class TestHTTPTransportConnect:
413
424
  with (
414
425
  patch("mcp.client.streamable_http.streamable_http_client", return_value=transport_cm),
415
426
  patch("mcp.ClientSession", return_value=session),
416
- patch("mcp.shared._httpx_utils.create_mcp_http_client") as mock_factory,
427
+ patch("httpx.AsyncClient") as mock_async_client,
417
428
  patch("httpx.Timeout") as mock_timeout,
418
429
  ):
419
430
  result = await adapter.connect(config)
@@ -421,10 +432,13 @@ class TestHTTPTransportConnect:
421
432
  assert result.is_ok
422
433
  # read timeout should be max(config.timeout, 300.0) for SSE streaming
423
434
  mock_timeout.assert_called_once_with(15.0, read=300.0)
424
- mock_factory.assert_called_once_with(
425
- headers=None,
426
- timeout=mock_timeout.return_value,
427
- )
435
+ mock_async_client.assert_called_once()
436
+ call_kwargs = mock_async_client.call_args.kwargs
437
+ # With no caller headers, we still set a default User-Agent so
438
+ # MCP servers can identify the ouroboros client in their logs.
439
+ assert call_kwargs["headers"]["User-Agent"].startswith("ouroboros-mcp-client/")
440
+ assert call_kwargs["timeout"] is mock_timeout.return_value
441
+ assert call_kwargs["follow_redirects"] is False
428
442
 
429
443
  @pytest.mark.asyncio
430
444
  async def test_http_disconnect_cleans_transport_on_error(self):
@@ -436,7 +450,7 @@ class TestHTTPTransportConnect:
436
450
  with (
437
451
  patch("mcp.client.streamable_http.streamable_http_client", return_value=transport_cm),
438
452
  patch("mcp.ClientSession", return_value=session),
439
- patch("mcp.shared._httpx_utils.create_mcp_http_client"),
453
+ patch("httpx.AsyncClient"),
440
454
  ):
441
455
  result = await adapter.connect(_make_http_config())
442
456