ouroboros-ai 0.27.3.dev1__tar.gz → 0.27.3.dev2__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 (648) hide show
  1. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/PKG-INFO +27 -17
  2. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/README.ko.md +2 -0
  3. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/README.md +3 -1
  4. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/cli-reference.md +0 -4
  5. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/getting-started.md +2 -1
  6. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/pyproject.toml +17 -11
  7. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/_version.py +2 -2
  8. ouroboros_ai-0.27.3.dev2/src/ouroboros/cli/formatters/prompting.py +38 -0
  9. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/config/loader.py +20 -1
  10. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/file_lock.py +5 -5
  11. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/server/adapter.py +60 -7
  12. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/mcp_tools.py +2 -1
  13. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/litellm_adapter.py +12 -0
  14. ouroboros_ai-0.27.3.dev2/tests/unit/cli/formatters/test_prompting.py +45 -0
  15. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/config/test_loader_env.py +16 -0
  16. ouroboros_ai-0.27.3.dev2/tests/unit/core/test_file_lock.py +52 -0
  17. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/server/test_adapter.py +29 -0
  18. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/test_litellm_adapter.py +20 -0
  19. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_dependencies_configured.py +19 -0
  20. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/uv.lock +506 -17
  21. ouroboros_ai-0.27.3.dev1/src/ouroboros/cli/formatters/prompting.py +0 -68
  22. ouroboros_ai-0.27.3.dev1/tests/unit/cli/formatters/test_prompting.py +0 -32
  23. ouroboros_ai-0.27.3.dev1/tests/unit/core/test_file_lock.py +0 -17
  24. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.claude/settings.json +0 -0
  25. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.claude-plugin/.mcp.json +0 -0
  26. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.claude-plugin/marketplace.json +0 -0
  27. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.claude-plugin/plugin.json +0 -0
  28. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.env.example +0 -0
  29. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  30. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  31. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  32. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  33. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/workflows/dev-publish.yml +0 -0
  34. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/workflows/lint.yml +0 -0
  35. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/workflows/release.yml +0 -0
  36. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.github/workflows/test.yml +0 -0
  37. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.gitignore +0 -0
  38. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.mcp.json +0 -0
  39. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.ouroboros/mechanical.toml +0 -0
  40. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.ouroboros/seeds/seed_73827177a2a3.yaml +0 -0
  41. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.ouroboros/seeds/seed_78c8e6e41813.yaml +0 -0
  42. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.pre-commit-config.yaml +0 -0
  43. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/.python-version +0 -0
  44. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/CHANGELOG.md +0 -0
  45. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/CLAUDE.md +0 -0
  46. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/CODE_OF_CONDUCT.md +0 -0
  47. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/CONTRIBUTING.md +0 -0
  48. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/HANDOFF.md +0 -0
  49. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/LICENSE +0 -0
  50. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/SECURITY.md +0 -0
  51. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/UNINSTALL.md +0 -0
  52. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/cancel.md +0 -0
  53. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/evaluate.md +0 -0
  54. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/evolve.md +0 -0
  55. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/help.md +0 -0
  56. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/interview.md +0 -0
  57. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/ralph.md +0 -0
  58. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/run.md +0 -0
  59. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/seed.md +0 -0
  60. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/setup.md +0 -0
  61. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/status.md +0 -0
  62. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/tutorial.md +0 -0
  63. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/unstuck.md +0 -0
  64. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/commands/welcome.md +0 -0
  65. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/.gitignore +0 -0
  66. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/Cargo.lock +0 -0
  67. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/Cargo.toml +0 -0
  68. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/README.md +0 -0
  69. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/db.rs +0 -0
  70. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/main.rs +0 -0
  71. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/mock.rs +0 -0
  72. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/state.rs +0 -0
  73. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/views/dashboard.rs +0 -0
  74. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/views/execution.rs +0 -0
  75. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/views/lineage.rs +0 -0
  76. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/views/logs.rs +0 -0
  77. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/views/mod.rs +0 -0
  78. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/crates/ouroboros-tui/src/views/session_selector.rs +0 -0
  79. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/README.md +0 -0
  80. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/api/README.md +0 -0
  81. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/api/core.md +0 -0
  82. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/api/mcp.md +0 -0
  83. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/architecture.md +0 -0
  84. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/config-reference.md +0 -0
  85. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/contributing/architecture-overview.md +0 -0
  86. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/contributing/findings-registry.md +0 -0
  87. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/contributing/issue-quality-policy.md +0 -0
  88. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/contributing/key-patterns.md +0 -0
  89. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/contributing/testing-guide.md +0 -0
  90. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/examples/mcp-config.yaml +0 -0
  91. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/guides/evaluation-pipeline.md +0 -0
  92. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/guides/evolution-loop.md +0 -0
  93. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/guides/issue-176-subagent-mcp-inheritance.md +0 -0
  94. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/guides/mcp-bridge.md +0 -0
  95. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/guides/seed-authoring.md +0 -0
  96. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/guides/tui-usage.md +0 -0
  97. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/images/PLACEHOLDER_README.md +0 -0
  98. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/images/ouroboros.png +0 -0
  99. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/platform-support.md +0 -0
  100. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/runtime-capability-matrix.md +0 -0
  101. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/runtime-guides/claude-code.md +0 -0
  102. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/runtime-guides/codex.md +0 -0
  103. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/docs/runtime-guides/opencode.md +0 -0
  104. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/coordinator_test_seed.yaml +0 -0
  105. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/dummy_seed.yaml +0 -0
  106. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/parallel_subac_test_seed.yaml +0 -0
  107. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/subac_test_seed.yaml +0 -0
  108. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/task_manager/README.md +0 -0
  109. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/task_manager/__init__.py +0 -0
  110. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/task_manager/__main__.py +0 -0
  111. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/task_manager/cli.py +0 -0
  112. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/task_manager/models.py +0 -0
  113. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/task_manager/storage.py +0 -0
  114. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/examples/test_display.py +0 -0
  115. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/hooks/hooks.json +0 -0
  116. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/llms-full.txt +0 -0
  117. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/llms.txt +0 -0
  118. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/project-context.md +0 -0
  119. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/drift-monitor.py +0 -0
  120. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/install.sh +0 -0
  121. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/keyword-detector.py +0 -0
  122. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/mcp-serve.sh +0 -0
  123. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/ralph-rewind.py +0 -0
  124. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/ralph.py +0 -0
  125. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/ralph.sh +0 -0
  126. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/session-start.py +0 -0
  127. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/sync-plugin-version.py +0 -0
  128. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/scripts/version-check.py +0 -0
  129. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/brownfield/SKILL.md +0 -0
  130. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/cancel/SKILL.md +0 -0
  131. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/evaluate/SKILL.md +0 -0
  132. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/evolve/SKILL.md +0 -0
  133. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/help/SKILL.md +0 -0
  134. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/interview/SKILL.md +0 -0
  135. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/pm/SKILL.md +0 -0
  136. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/publish/SKILL.md +0 -0
  137. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/qa/SKILL.md +0 -0
  138. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/ralph/SKILL.md +0 -0
  139. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/run/SKILL.md +0 -0
  140. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/seed/SKILL.md +0 -0
  141. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/setup/SKILL.md +0 -0
  142. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/status/SKILL.md +0 -0
  143. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/tutorial/SKILL.md +0 -0
  144. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/unstuck/SKILL.md +0 -0
  145. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/update/SKILL.md +0 -0
  146. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/skills/welcome/SKILL.md +0 -0
  147. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/__init__.py +0 -0
  148. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/__main__.py +0 -0
  149. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/__init__.py +0 -0
  150. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/advocate.md +0 -0
  151. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/analysis-agent.md +0 -0
  152. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/architect.md +0 -0
  153. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/breadth-keeper.md +0 -0
  154. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/code-executor.md +0 -0
  155. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/codebase-explorer.md +0 -0
  156. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/consensus-reviewer.md +0 -0
  157. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/contrarian.md +0 -0
  158. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/evaluator.md +0 -0
  159. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/hacker.md +0 -0
  160. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/judge.md +0 -0
  161. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/loader.py +0 -0
  162. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/ontologist.md +0 -0
  163. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/ontology-analyst.md +0 -0
  164. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/qa-judge.md +0 -0
  165. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/research-agent.md +0 -0
  166. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/researcher.md +0 -0
  167. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/seed-architect.md +0 -0
  168. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/seed-closer.md +0 -0
  169. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/semantic-evaluator.md +0 -0
  170. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/simplifier.md +0 -0
  171. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/agents/socratic-interviewer.md +0 -0
  172. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/__init__.py +0 -0
  173. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/ambiguity.py +0 -0
  174. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/brownfield.py +0 -0
  175. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/explore.py +0 -0
  176. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/interview.py +0 -0
  177. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/pm_completion.py +0 -0
  178. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/pm_document.py +0 -0
  179. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/pm_interview.py +0 -0
  180. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/pm_seed.py +0 -0
  181. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/question_classifier.py +0 -0
  182. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/bigbang/seed_generator.py +0 -0
  183. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/__init__.py +0 -0
  184. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/__init__.py +0 -0
  185. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/cancel.py +0 -0
  186. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/config.py +0 -0
  187. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/init.py +0 -0
  188. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/mcp.py +0 -0
  189. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/pm.py +0 -0
  190. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/run.py +0 -0
  191. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/setup.py +0 -0
  192. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/status.py +0 -0
  193. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/tui.py +0 -0
  194. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/commands/uninstall.py +0 -0
  195. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/formatters/__init__.py +0 -0
  196. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/formatters/panels.py +0 -0
  197. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/formatters/progress.py +0 -0
  198. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/formatters/tables.py +0 -0
  199. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/formatters/workflow_display.py +0 -0
  200. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/jsonc.py +0 -0
  201. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/cli/main.py +0 -0
  202. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/codex/__init__.py +0 -0
  203. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/codex/artifacts.py +0 -0
  204. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/codex/ouroboros.md +0 -0
  205. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/codex_permissions.py +0 -0
  206. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/config/__init__.py +0 -0
  207. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/config/models.py +0 -0
  208. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/__init__.py +0 -0
  209. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/ac_tree.py +0 -0
  210. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/context.py +0 -0
  211. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/errors.py +0 -0
  212. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/git_workflow.py +0 -0
  213. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/initial_context.py +0 -0
  214. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/json_utils.py +0 -0
  215. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/lineage.py +0 -0
  216. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/ontology_aspect.py +0 -0
  217. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/ontology_questions.py +0 -0
  218. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/project_paths.py +0 -0
  219. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/retry.py +0 -0
  220. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/security.py +0 -0
  221. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/seed.py +0 -0
  222. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/text.py +0 -0
  223. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/ttl_cache.py +0 -0
  224. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/types.py +0 -0
  225. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/core/worktree.py +0 -0
  226. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/__init__.py +0 -0
  227. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/artifact_collector.py +0 -0
  228. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/consensus.py +0 -0
  229. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/json_utils.py +0 -0
  230. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/languages.py +0 -0
  231. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/mechanical.py +0 -0
  232. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/models.py +0 -0
  233. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/pipeline.py +0 -0
  234. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/semantic.py +0 -0
  235. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/trigger.py +0 -0
  236. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evaluation/verification_artifacts.py +0 -0
  237. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/events/__init__.py +0 -0
  238. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/events/base.py +0 -0
  239. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/events/decomposition.py +0 -0
  240. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/events/evaluation.py +0 -0
  241. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/events/interview.py +0 -0
  242. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/events/lineage.py +0 -0
  243. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/events/ontology.py +0 -0
  244. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evolution/__init__.py +0 -0
  245. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evolution/convergence.py +0 -0
  246. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evolution/loop.py +0 -0
  247. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evolution/projector.py +0 -0
  248. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evolution/reflect.py +0 -0
  249. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evolution/regression.py +0 -0
  250. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/evolution/wonder.py +0 -0
  251. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/execution/__init__.py +0 -0
  252. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/execution/atomicity.py +0 -0
  253. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/execution/decomposition.py +0 -0
  254. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/execution/double_diamond.py +0 -0
  255. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/execution/subagent.py +0 -0
  256. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/__init__.py +0 -0
  257. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/bridge/__init__.py +0 -0
  258. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/bridge/bridge.py +0 -0
  259. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/bridge/config.py +0 -0
  260. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/bridge/factory.py +0 -0
  261. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/client/__init__.py +0 -0
  262. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/client/adapter.py +0 -0
  263. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/client/manager.py +0 -0
  264. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/client/protocol.py +0 -0
  265. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/errors.py +0 -0
  266. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/job_manager.py +0 -0
  267. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/resources/__init__.py +0 -0
  268. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/resources/handlers.py +0 -0
  269. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/server/__init__.py +0 -0
  270. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/server/protocol.py +0 -0
  271. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/server/security.py +0 -0
  272. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/__init__.py +0 -0
  273. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/ac_tree_hud_handler.py +0 -0
  274. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/ac_tree_hud_render.py +0 -0
  275. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/authoring_handlers.py +0 -0
  276. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/bridge_mixin.py +0 -0
  277. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/brownfield_handler.py +0 -0
  278. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/dashboard.py +0 -0
  279. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/definitions.py +0 -0
  280. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/evaluation_handlers.py +0 -0
  281. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/evolution_handlers.py +0 -0
  282. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/execution_handlers.py +0 -0
  283. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/job_handlers.py +0 -0
  284. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/pm_handler.py +0 -0
  285. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/qa.py +0 -0
  286. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/query_handlers.py +0 -0
  287. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/tools/registry.py +0 -0
  288. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/mcp/types.py +0 -0
  289. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/observability/__init__.py +0 -0
  290. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/observability/drift.py +0 -0
  291. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/observability/logging.py +0 -0
  292. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/observability/retrospective.py +0 -0
  293. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/__init__.py +0 -0
  294. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/adapter.py +0 -0
  295. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/capabilities.py +0 -0
  296. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/codex_cli_runtime.py +0 -0
  297. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/command_dispatcher.py +0 -0
  298. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/control_plane.py +0 -0
  299. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/coordinator.py +0 -0
  300. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/dependency_analyzer.py +0 -0
  301. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/events.py +0 -0
  302. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/execution_runtime_scope.py +0 -0
  303. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/execution_strategy.py +0 -0
  304. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/heartbeat.py +0 -0
  305. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/level_context.py +0 -0
  306. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/mcp_config.py +0 -0
  307. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/opencode_event_normalizer.py +0 -0
  308. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/opencode_runtime.py +0 -0
  309. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/parallel_executor.py +0 -0
  310. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/parallel_executor_models.py +0 -0
  311. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/policy.py +0 -0
  312. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/runner.py +0 -0
  313. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/runtime_factory.py +0 -0
  314. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/runtime_message_projection.py +0 -0
  315. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/session.py +0 -0
  316. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/orchestrator/workflow_state.py +0 -0
  317. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/__init__.py +0 -0
  318. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/brownfield.py +0 -0
  319. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/checkpoint.py +0 -0
  320. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/event_store.py +0 -0
  321. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/migrations/__init__.py +0 -0
  322. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/migrations/runner.py +0 -0
  323. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/migrations/scripts/001_initial.sql +0 -0
  324. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/migrations/scripts/002_brownfield.sql +0 -0
  325. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/schema.py +0 -0
  326. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/persistence/uow.py +0 -0
  327. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/__init__.py +0 -0
  328. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/agents/__init__.py +0 -0
  329. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/agents/pool.py +0 -0
  330. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/agents/registry.py +0 -0
  331. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/orchestration/__init__.py +0 -0
  332. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/orchestration/router.py +0 -0
  333. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/orchestration/scheduler.py +0 -0
  334. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/skills/__init__.py +0 -0
  335. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/skills/docs.py +0 -0
  336. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/skills/executor.py +0 -0
  337. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/skills/keywords.py +0 -0
  338. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/plugin/skills/registry.py +0 -0
  339. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/pm/__init__.py +0 -0
  340. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/pm/handoff.py +0 -0
  341. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/pm/renderer.py +0 -0
  342. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/__init__.py +0 -0
  343. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/anthropic_adapter.py +0 -0
  344. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/base.py +0 -0
  345. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/claude_code_adapter.py +0 -0
  346. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/codex_cli_adapter.py +0 -0
  347. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/codex_cli_stream.py +0 -0
  348. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/factory.py +0 -0
  349. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/gemini_cli_adapter.py +0 -0
  350. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/providers/opencode_adapter.py +0 -0
  351. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/py.typed +0 -0
  352. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/resilience/__init__.py +0 -0
  353. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/resilience/lateral.py +0 -0
  354. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/resilience/stagnation.py +0 -0
  355. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/routing/__init__.py +0 -0
  356. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/routing/complexity.py +0 -0
  357. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/routing/downgrade.py +0 -0
  358. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/routing/escalation.py +0 -0
  359. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/routing/router.py +0 -0
  360. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/routing/tiers.py +0 -0
  361. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/secondary/__init__.py +0 -0
  362. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/secondary/scheduler.py +0 -0
  363. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/secondary/todo_registry.py +0 -0
  364. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/strategies/__init__.py +0 -0
  365. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/strategies/devil_advocate.py +0 -0
  366. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/__init__.py +0 -0
  367. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/app.py +0 -0
  368. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/components/__init__.py +0 -0
  369. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/components/agents_panel.py +0 -0
  370. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/components/event_log.py +0 -0
  371. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/components/progress.py +0 -0
  372. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/components/token_tracker.py +0 -0
  373. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/events.py +0 -0
  374. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/__init__.py +0 -0
  375. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/confirm_rewind.py +0 -0
  376. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/dashboard.py +0 -0
  377. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/dashboard_v2.py +0 -0
  378. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/dashboard_v3.py +0 -0
  379. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/debug.py +0 -0
  380. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/execution.py +0 -0
  381. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/hud_dashboard.py +0 -0
  382. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/lineage_detail.py +0 -0
  383. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/lineage_selector.py +0 -0
  384. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/logs.py +0 -0
  385. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/screens/session_selector.py +0 -0
  386. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/__init__.py +0 -0
  387. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/ac_progress.py +0 -0
  388. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/ac_tree.py +0 -0
  389. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/agent_activity.py +0 -0
  390. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/cost_tracker.py +0 -0
  391. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/drift_meter.py +0 -0
  392. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/lineage_tree.py +0 -0
  393. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/parallel_graph.py +0 -0
  394. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/tui/widgets/phase_progress.py +0 -0
  395. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/verification/__init__.py +0 -0
  396. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/verification/extractor.py +0 -0
  397. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/verification/models.py +0 -0
  398. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/src/ouroboros/verification/verifier.py +0 -0
  399. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/__init__.py +0 -0
  400. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/conftest.py +0 -0
  401. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/e2e/__init__.py +0 -0
  402. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/e2e/conftest.py +0 -0
  403. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/e2e/mcp_bridge_test_config.yaml +0 -0
  404. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/e2e/test_cli_commands.py +0 -0
  405. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/e2e/test_full_workflow.py +0 -0
  406. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/e2e/test_session_persistence.py +0 -0
  407. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/fixtures/test_atomicity_seed.yml +0 -0
  408. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/__init__.py +0 -0
  409. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/conftest.py +0 -0
  410. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/mcp/__init__.py +0 -0
  411. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/mcp/bridge/__init__.py +0 -0
  412. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/mcp/bridge/test_bridge_server_to_server.py +0 -0
  413. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/mcp/conftest.py +0 -0
  414. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/mcp/test_client_adapter.py +0 -0
  415. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/mcp/test_client_manager.py +0 -0
  416. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/mcp/test_server_adapter.py +0 -0
  417. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/plugin/test_orchestration.py +0 -0
  418. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/test_codex_cli_passthrough_smoke.py +0 -0
  419. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/test_codex_skill_fallback.py +0 -0
  420. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/test_codex_skill_smoke.py +0 -0
  421. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/integration/test_entry_point.py +0 -0
  422. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/__init__.py +0 -0
  423. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/agents/__init__.py +0 -0
  424. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/agents/test_loader.py +0 -0
  425. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/__init__.py +0 -0
  426. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_ambiguity.py +0 -0
  427. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_brownfield.py +0 -0
  428. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_classifier_context.py +0 -0
  429. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_decide_later_items.py +0 -0
  430. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_explore.py +0 -0
  431. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_interview.py +0 -0
  432. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_interview_async_io.py +0 -0
  433. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_interview_no_web_search_hint.py +0 -0
  434. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_interview_research_prefix.py +0 -0
  435. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_pm_completion.py +0 -0
  436. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_pm_document_generator.py +0 -0
  437. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_pm_document_writer.py +0 -0
  438. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_pm_interview.py +0 -0
  439. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_pm_interview_brownfield_db.py +0 -0
  440. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_pm_seed_ac12.py +0 -0
  441. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_pm_seed_save.py +0 -0
  442. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_question_classifier.py +0 -0
  443. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/bigbang/test_seed_generator.py +0 -0
  444. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/__init__.py +0 -0
  445. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/commands/test_tui_command.py +0 -0
  446. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/formatters/__init__.py +0 -0
  447. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/formatters/test_console.py +0 -0
  448. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/formatters/test_panels.py +0 -0
  449. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/formatters/test_progress.py +0 -0
  450. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/formatters/test_tables.py +0 -0
  451. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/formatters/test_workflow_display.py +0 -0
  452. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_cancel.py +0 -0
  453. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_config.py +0 -0
  454. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_init_pm_seed_detection.py +0 -0
  455. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_init_runtime.py +0 -0
  456. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_jsonc.py +0 -0
  457. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_main.py +0 -0
  458. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_mcp_nested_guard.py +0 -0
  459. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_mcp_startup_cleanup.py +0 -0
  460. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm.py +0 -0
  461. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm_brownfield.py +0 -0
  462. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm_completion.py +0 -0
  463. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm_interactive_logging.py +0 -0
  464. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm_missing_litellm.py +0 -0
  465. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm_overwrite.py +0 -0
  466. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm_runtime_adapter.py +0 -0
  467. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_pm_select_repos.py +0 -0
  468. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_run_qa.py +0 -0
  469. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_setup.py +0 -0
  470. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/cli/test_uninstall.py +0 -0
  471. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/config/__init__.py +0 -0
  472. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/config/test_loader.py +0 -0
  473. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/config/test_models.py +0 -0
  474. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/__init__.py +0 -0
  475. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_ac_tree.py +0 -0
  476. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_context.py +0 -0
  477. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_errors.py +0 -0
  478. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_git_workflow.py +0 -0
  479. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_initial_context.py +0 -0
  480. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_lineage.py +0 -0
  481. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_ontology_aspect.py +0 -0
  482. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_ontology_questions.py +0 -0
  483. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_retry.py +0 -0
  484. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_security.py +0 -0
  485. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_seed.py +0 -0
  486. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_ttl_cache.py +0 -0
  487. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_types.py +0 -0
  488. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/core/test_worktree.py +0 -0
  489. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/__init__.py +0 -0
  490. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_artifact_collector_file_prefix.py +0 -0
  491. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_consensus.py +0 -0
  492. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_json_utils.py +0 -0
  493. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_languages.py +0 -0
  494. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_mechanical.py +0 -0
  495. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_models.py +0 -0
  496. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_pipeline_trigger_consensus.py +0 -0
  497. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_review_fixes.py +0 -0
  498. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_semantic.py +0 -0
  499. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_trigger.py +0 -0
  500. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_trigger_consensus.py +0 -0
  501. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evaluation/test_verification_artifacts.py +0 -0
  502. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/events/__init__.py +0 -0
  503. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/events/test_base.py +0 -0
  504. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/events/test_decomposition_events.py +0 -0
  505. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/evolution/test_wonder_scope.py +0 -0
  506. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/execution/__init__.py +0 -0
  507. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/execution/test_atomicity.py +0 -0
  508. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/execution/test_decomposition.py +0 -0
  509. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/execution/test_double_diamond.py +0 -0
  510. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/execution/test_subagent_isolation.py +0 -0
  511. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/__init__.py +0 -0
  512. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/bridge/__init__.py +0 -0
  513. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/bridge/test_bridge.py +0 -0
  514. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/bridge/test_config.py +0 -0
  515. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/bridge/test_factory.py +0 -0
  516. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/bridge/test_handler_wiring.py +0 -0
  517. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/bridge/test_stability.py +0 -0
  518. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/client/__init__.py +0 -0
  519. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/client/test_adapter.py +0 -0
  520. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/client/test_adapter_transport_lifecycle.py +0 -0
  521. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/client/test_manager.py +0 -0
  522. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/conftest.py +0 -0
  523. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/server/__init__.py +0 -0
  524. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/server/test_security.py +0 -0
  525. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/test_errors.py +0 -0
  526. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/test_job_manager.py +0 -0
  527. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/test_types.py +0 -0
  528. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/__init__.py +0 -0
  529. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/conftest.py +0 -0
  530. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_footer.py +0 -0
  531. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_handler.py +0 -0
  532. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_handler_completed.py +0 -0
  533. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_handler_cursor_changed.py +0 -0
  534. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_handler_invalid_session.py +0 -0
  535. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_handler_no_execution.py +0 -0
  536. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_handler_waiting.py +0 -0
  537. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_max_nodes.py +0 -0
  538. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_render_depth2.py +0 -0
  539. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_render_depth3.py +0 -0
  540. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_status_icons.py +0 -0
  541. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_ac_tree_hud_truncation.py +0 -0
  542. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_brownfield_handler.py +0 -0
  543. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_definitions.py +0 -0
  544. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_evaluation_handler.py +0 -0
  545. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_interview_parallel_scoring.py +0 -0
  546. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_interview_scoring_guard.py +0 -0
  547. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_mcp_manager_wiring.py +0 -0
  548. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_pm_handler.py +0 -0
  549. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_pm_handler_generate.py +0 -0
  550. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_pm_handler_pending_reframe.py +0 -0
  551. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_qa_integration.py +0 -0
  552. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_qa_parser.py +0 -0
  553. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_registry.py +0 -0
  554. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/mcp/tools/test_traceback_reporting.py +0 -0
  555. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/observability/__init__.py +0 -0
  556. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/observability/test_drift.py +0 -0
  557. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/observability/test_logging.py +0 -0
  558. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/observability/test_retrospective.py +0 -0
  559. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/__init__.py +0 -0
  560. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_adapter.py +0 -0
  561. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_capabilities.py +0 -0
  562. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_codex_cli_runtime.py +0 -0
  563. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_codex_recursion_guard.py +0 -0
  564. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_command_dispatcher.py +0 -0
  565. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_control_plane.py +0 -0
  566. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_coordinator.py +0 -0
  567. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_dependency_analyzer.py +0 -0
  568. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_events.py +0 -0
  569. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_execution_runtime_scope.py +0 -0
  570. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_execution_strategy.py +0 -0
  571. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_inflight_cancellation.py +0 -0
  572. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_level_context.py +0 -0
  573. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_mcp_config.py +0 -0
  574. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_mcp_tools.py +0 -0
  575. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_opencode_runtime.py +0 -0
  576. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_parallel_executor.py +0 -0
  577. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_parallel_executor_atomic_judgment.py +0 -0
  578. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_parallel_executor_recursive_depth.py +0 -0
  579. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_parallel_executor_retry_resume.py +0 -0
  580. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_policy.py +0 -0
  581. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_runner.py +0 -0
  582. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_runner_cancellation.py +0 -0
  583. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_runtime_factory.py +0 -0
  584. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_runtime_message_projection.py +0 -0
  585. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_session.py +0 -0
  586. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/orchestrator/test_workflow_state.py +0 -0
  587. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/persistence/__init__.py +0 -0
  588. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/persistence/test_brownfield_store.py +0 -0
  589. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/persistence/test_checkpoint.py +0 -0
  590. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/persistence/test_event_store.py +0 -0
  591. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/persistence/test_schema.py +0 -0
  592. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/persistence/test_uow.py +0 -0
  593. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/__init__.py +0 -0
  594. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/agents/__init__.py +0 -0
  595. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/agents/test_registry.py +0 -0
  596. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/orchestration/__init__.py +0 -0
  597. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/orchestration/test_model_router.py +0 -0
  598. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/skills/__init__.py +0 -0
  599. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/skills/test_keywords.py +0 -0
  600. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/plugin/skills/test_registry.py +0 -0
  601. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/pm/__init__.py +0 -0
  602. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/pm/test_renderer.py +0 -0
  603. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/__init__.py +0 -0
  604. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/test_base.py +0 -0
  605. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/test_claude_code_adapter.py +0 -0
  606. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/test_codex_cli_adapter.py +0 -0
  607. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/test_factory.py +0 -0
  608. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/test_gemini_cli_adapter.py +0 -0
  609. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/providers/test_opencode_adapter.py +0 -0
  610. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/resilience/__init__.py +0 -0
  611. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/resilience/test_lateral.py +0 -0
  612. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/resilience/test_stagnation.py +0 -0
  613. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/routing/__init__.py +0 -0
  614. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/routing/test_complexity.py +0 -0
  615. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/routing/test_downgrade.py +0 -0
  616. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/routing/test_escalation.py +0 -0
  617. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/routing/test_router.py +0 -0
  618. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/routing/test_tiers.py +0 -0
  619. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/scripts/test_keyword_detector.py +0 -0
  620. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/scripts/test_version_check.py +0 -0
  621. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/secondary/__init__.py +0 -0
  622. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/secondary/test_scheduler.py +0 -0
  623. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/secondary/test_todo_registry.py +0 -0
  624. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_artifact_collector.py +0 -0
  625. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_codex_artifacts.py +0 -0
  626. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_convergence.py +0 -0
  627. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_dashboard.py +0 -0
  628. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_evolve_rewind.py +0 -0
  629. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_evolve_step.py +0 -0
  630. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_graceful_shutdown.py +0 -0
  631. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_main_entry_point.py +0 -0
  632. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_module_structure.py +0 -0
  633. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_project_initialization.py +0 -0
  634. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_projector_rewind.py +0 -0
  635. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_ralph_parser.py +0 -0
  636. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_ralph_rewind.py +0 -0
  637. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_regression.py +0 -0
  638. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_tooling_configuration.py +0 -0
  639. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/test_verification.py +0 -0
  640. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/__init__.py +0 -0
  641. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/test_app.py +0 -0
  642. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/test_cancelled_display.py +0 -0
  643. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/test_events.py +0 -0
  644. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/test_lineage_viewer.py +0 -0
  645. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/test_screens.py +0 -0
  646. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/test_session_selector_replay.py +0 -0
  647. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tests/unit/tui/test_widgets.py +0 -0
  648. {ouroboros_ai-0.27.3.dev1 → ouroboros_ai-0.27.3.dev2}/tools/sync_github_project.py +0 -0
@@ -1,32 +1,40 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ouroboros-ai
3
- Version: 0.27.3.dev1
3
+ Version: 0.27.3.dev2
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
7
7
  Requires-Python: >=3.12
8
- Requires-Dist: aiosqlite>=0.20.0
9
- Requires-Dist: pydantic>=2.0.0
10
- Requires-Dist: pyyaml>=6.0.0
11
- Requires-Dist: rich>=13.0.0
12
- Requires-Dist: sqlalchemy[asyncio]>=2.0.0
13
- Requires-Dist: structlog>=24.0.0
14
- Requires-Dist: typer>=0.12.0
8
+ Requires-Dist: aiosqlite<1.0.0,>=0.20.0
9
+ Requires-Dist: prompt-toolkit<4.0.0,>=3.0.0
10
+ Requires-Dist: pydantic<3.0.0,>=2.0.0
11
+ Requires-Dist: pyyaml<7.0.0,>=6.0.0
12
+ Requires-Dist: rich<15.0.0,>=13.0.0
13
+ Requires-Dist: sqlalchemy[asyncio]<3.0.0,>=2.0.0
14
+ Requires-Dist: structlog<26.0.0,>=24.0.0
15
+ Requires-Dist: typer<1.0.0,>=0.12.0
15
16
  Provides-Extra: all
16
- Requires-Dist: anthropic>=0.52.0; extra == 'all'
17
- Requires-Dist: claude-agent-sdk>=0.1.0; extra == 'all'
17
+ Requires-Dist: anthropic<1.0.0,>=0.52.0; extra == 'all'
18
+ Requires-Dist: claude-agent-sdk<1.0.0,>=0.1.0; extra == 'all'
18
19
  Requires-Dist: litellm<=1.82.6,>=1.80.0; extra == 'all'
19
- Requires-Dist: mcp>=1.26.0; extra == 'all'
20
- Requires-Dist: textual>=1.0.0; extra == 'all'
20
+ Requires-Dist: mcp<2.0.0,>=1.26.0; extra == 'all'
21
+ Requires-Dist: pandas<3.0.0,>=2.2.0; extra == 'all'
22
+ Requires-Dist: plotly<7.0.0,>=5.24.0; extra == 'all'
23
+ Requires-Dist: streamlit<2.0.0,>=1.40.0; extra == 'all'
24
+ Requires-Dist: textual<9.0.0,>=1.0.0; extra == 'all'
21
25
  Provides-Extra: claude
22
- Requires-Dist: anthropic>=0.52.0; extra == 'claude'
23
- Requires-Dist: claude-agent-sdk>=0.1.0; extra == 'claude'
26
+ Requires-Dist: anthropic<1.0.0,>=0.52.0; extra == 'claude'
27
+ Requires-Dist: claude-agent-sdk<1.0.0,>=0.1.0; extra == 'claude'
28
+ Provides-Extra: dashboard
29
+ Requires-Dist: pandas<3.0.0,>=2.2.0; extra == 'dashboard'
30
+ Requires-Dist: plotly<7.0.0,>=5.24.0; extra == 'dashboard'
31
+ Requires-Dist: streamlit<2.0.0,>=1.40.0; extra == 'dashboard'
24
32
  Provides-Extra: litellm
25
33
  Requires-Dist: litellm<=1.82.6,>=1.80.0; extra == 'litellm'
26
34
  Provides-Extra: mcp
27
- Requires-Dist: mcp>=1.26.0; extra == 'mcp'
35
+ Requires-Dist: mcp<2.0.0,>=1.26.0; extra == 'mcp'
28
36
  Provides-Extra: tui
29
- Requires-Dist: textual>=1.0.0; extra == 'tui'
37
+ Requires-Dist: textual<9.0.0,>=1.0.0; extra == 'tui'
30
38
  Description-Content-Type: text/markdown
31
39
 
32
40
  <p align="right">
@@ -128,10 +136,12 @@ pip install ouroboros-ai[claude] # + Claude Code deps
128
136
  pip install ouroboros-ai[litellm] # + LiteLLM multi-provider
129
137
  pip install ouroboros-ai[mcp] # + MCP server/client support
130
138
  pip install ouroboros-ai[tui] # + Textual terminal UI
131
- pip install ouroboros-ai[all] # everything
139
+ pip install ouroboros-ai[all] # everything (claude + litellm + mcp + tui + dashboard)
132
140
  ouroboros setup # configure runtime
133
141
  ```
134
142
 
143
+ Legacy compatibility: `ouroboros-ai[dashboard]` is still accepted as a compatibility alias while extras migrate.
144
+
135
145
  See runtime guides: [Claude Code](./docs/runtime-guides/claude-code.md) · [Codex CLI](./docs/runtime-guides/codex.md)
136
146
 
137
147
  </details>
@@ -125,6 +125,8 @@ pip install ouroboros-ai[all] # 전부
125
125
  ouroboros setup # 런타임 설정
126
126
  ```
127
127
 
128
+ 호환성 참고: extras 전환 기간 동안 `ouroboros-ai[dashboard]`도 no-op alias로 계속 허용됩니다.
129
+
128
130
  런타임별 가이드: [Claude Code](./docs/runtime-guides/claude-code.md) · [Codex CLI](./docs/runtime-guides/codex.md)
129
131
 
130
132
  </details>
@@ -97,10 +97,12 @@ pip install ouroboros-ai[claude] # + Claude Code deps
97
97
  pip install ouroboros-ai[litellm] # + LiteLLM multi-provider
98
98
  pip install ouroboros-ai[mcp] # + MCP server/client support
99
99
  pip install ouroboros-ai[tui] # + Textual terminal UI
100
- pip install ouroboros-ai[all] # everything
100
+ pip install ouroboros-ai[all] # everything (claude + litellm + mcp + tui + dashboard)
101
101
  ouroboros setup # configure runtime
102
102
  ```
103
103
 
104
+ Legacy compatibility: `ouroboros-ai[dashboard]` is still accepted as a compatibility alias while extras migrate.
105
+
104
106
  See runtime guides: [Claude Code](./docs/runtime-guides/claude-code.md) · [Codex CLI](./docs/runtime-guides/codex.md)
105
107
 
106
108
  </details>
@@ -160,10 +160,6 @@ ouroboros init start --resume interview_20260116_120000
160
160
  ouroboros init
161
161
  ```
162
162
 
163
- > **Interactive multiline input:** when `init` or other interview-style commands prompt for a
164
- > longer response, press `Ctrl+D` (macOS/Linux) or `Ctrl+Z` then Enter (Windows) to submit the
165
- > full response. Plain Enter inserts a newline.
166
-
167
163
  ### `init list`
168
164
 
169
165
  List all interview sessions.
@@ -82,13 +82,14 @@ pip install ouroboros-ai[claude] # + Claude Code runtime deps (anthropic, c
82
82
  pip install ouroboros-ai[litellm] # + LiteLLM multi-provider support (100+ models)
83
83
  pip install ouroboros-ai[mcp] # + MCP server/client runtime support
84
84
  pip install ouroboros-ai[tui] # + Textual terminal UI
85
- pip install ouroboros-ai[all] # Everything (claude + litellm + mcp + tui)
85
+ pip install ouroboros-ai[all] # Everything (claude + litellm + mcp + tui + dashboard)
86
86
 
87
87
  ouroboros --version # verify CLI
88
88
  ```
89
89
 
90
90
  > **Which extra do I need?** If you only use Claude Code as your runtime, `ouroboros-ai[claude]` is sufficient.
91
91
  > For multi-model support via LiteLLM, use `ouroboros-ai[litellm]` or just grab everything with `ouroboros-ai[all]`.
92
+ > Legacy note: `ouroboros-ai[dashboard]` is still accepted as a compatibility extra during the extras transition.
92
93
 
93
94
  **One-liner alternative** (auto-detects your runtime and installs matching extras):
94
95
  ```bash
@@ -8,21 +8,27 @@ authors = [
8
8
  ]
9
9
  requires-python = ">=3.12"
10
10
  dependencies = [
11
- "aiosqlite>=0.20.0",
12
- "pydantic>=2.0.0",
13
- "pyyaml>=6.0.0",
14
- "rich>=13.0.0",
15
- "sqlalchemy[asyncio]>=2.0.0",
16
- "structlog>=24.0.0",
17
- "typer>=0.12.0",
11
+ "aiosqlite>=0.20.0,<1.0.0",
12
+ "pydantic>=2.0.0,<3.0.0",
13
+ "prompt-toolkit>=3.0.0,<4.0.0",
14
+ "pyyaml>=6.0.0,<7.0.0",
15
+ "rich>=13.0.0,<15.0.0",
16
+ "sqlalchemy[asyncio]>=2.0.0,<3.0.0",
17
+ "structlog>=24.0.0,<26.0.0",
18
+ "typer>=0.12.0,<1.0.0",
18
19
  ]
19
20
 
20
21
  [project.optional-dependencies]
21
- claude = ["claude-agent-sdk>=0.1.0", "anthropic>=0.52.0"]
22
+ claude = ["claude-agent-sdk>=0.1.0,<1.0.0", "anthropic>=0.52.0,<1.0.0"]
22
23
  litellm = ["litellm>=1.80.0,<=1.82.6"]
23
- mcp = ["mcp>=1.26.0"]
24
- tui = ["textual>=1.0.0"]
25
- all = ["ouroboros-ai[claude,litellm,mcp,tui]"]
24
+ dashboard = [
25
+ "streamlit>=1.40.0,<2.0.0",
26
+ "plotly>=5.24.0,<7.0.0",
27
+ "pandas>=2.2.0,<3.0.0",
28
+ ]
29
+ mcp = ["mcp>=1.26.0,<2.0.0"]
30
+ tui = ["textual>=1.0.0,<9.0.0"]
31
+ all = ["ouroboros-ai[claude,litellm,mcp,tui,dashboard]"]
26
32
 
27
33
  [project.scripts]
28
34
  ouroboros = "ouroboros.cli.main:app"
@@ -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.27.3.dev1'
22
- __version_tuple__ = version_tuple = (0, 27, 3, 'dev1')
21
+ __version__ = version = '0.27.3.dev2'
22
+ __version_tuple__ = version_tuple = (0, 27, 3, 'dev2')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -0,0 +1,38 @@
1
+ """Prompt helpers for interactive CLI input."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from prompt_toolkit import PromptSession
6
+ from prompt_toolkit.key_binding import KeyBindings, KeyPressEvent
7
+ from prompt_toolkit.patch_stdout import patch_stdout
8
+
9
+ from ouroboros.cli.formatters import console
10
+
11
+
12
+ async def multiline_prompt_async(prompt_text: str) -> str:
13
+ """Get multiline-safe input while allowing logs above the active prompt."""
14
+ bindings = KeyBindings()
15
+
16
+ @bindings.add("c-j")
17
+ def insert_newline(event: KeyPressEvent) -> None:
18
+ event.current_buffer.insert_text("\n")
19
+
20
+ @bindings.add("c-m")
21
+ def submit(event: KeyPressEvent) -> None:
22
+ event.current_buffer.validate_and_handle()
23
+
24
+ console.print(f"[bold green]{prompt_text}[/] [dim](Enter: submit, Ctrl+J: newline)[/]")
25
+
26
+ session: PromptSession[str] = PromptSession(
27
+ message="> ",
28
+ multiline=True,
29
+ prompt_continuation=" ",
30
+ key_bindings=bindings,
31
+ )
32
+
33
+ # prompt_toolkit proxies both stdout and stderr above the prompt.
34
+ with patch_stdout(raw=True):
35
+ return await session.prompt_async()
36
+
37
+
38
+ __all__ = ["multiline_prompt_async"]
@@ -54,6 +54,8 @@ from ouroboros.core.errors import ConfigError # noqa: E402
54
54
  _CODEX_LLM_BACKENDS = frozenset({"codex", "codex_cli", "opencode", "opencode_cli"})
55
55
  _OPENCODE_BACKENDS = frozenset({"opencode", "opencode_cli"})
56
56
  _CODEX_DEFAULT_MODEL = "default"
57
+ _PLACEHOLDER_API_KEY_PREFIX = "YOUR_"
58
+ _PLACEHOLDER_API_KEY_SUFFIX = "_API_KEY"
57
59
  _DEFAULT_CONSENSUS_MODELS = (
58
60
  "openrouter/openai/gpt-4o",
59
61
  "openrouter/anthropic/claude-opus-4-6",
@@ -82,6 +84,16 @@ def _parse_env_value(raw_value: str) -> str:
82
84
  return candidate.rstrip()
83
85
 
84
86
 
87
+ def _is_placeholder_api_key(value: str) -> bool:
88
+ """Treat common template placeholders as unset."""
89
+ candidate = value.strip()
90
+ return bool(
91
+ candidate
92
+ and candidate.startswith(_PLACEHOLDER_API_KEY_PREFIX)
93
+ and candidate.endswith(_PLACEHOLDER_API_KEY_SUFFIX)
94
+ )
95
+
96
+
85
97
  def _load_env_file(path: Path) -> None:
86
98
  if not path.exists():
87
99
  return
@@ -99,7 +111,14 @@ def _load_env_file(path: Path) -> None:
99
111
  key = key.strip()
100
112
  if not key or any(ch.isspace() for ch in key):
101
113
  continue
102
- os.environ.setdefault(key, _parse_env_value(raw_value))
114
+
115
+ parsed_value = _parse_env_value(raw_value)
116
+ if not parsed_value or _is_placeholder_api_key(parsed_value):
117
+ continue
118
+
119
+ current_value = os.environ.get(key)
120
+ if current_value is None or _is_placeholder_api_key(current_value):
121
+ os.environ[key] = parsed_value
103
122
 
104
123
 
105
124
  for env_path in (Path(".env"), Path.home() / ".ouroboros" / ".env"):
@@ -15,14 +15,14 @@ else: # pragma: no branch
15
15
 
16
16
 
17
17
  @contextmanager
18
- def file_lock(file_path: Path, exclusive: bool = True) -> Iterator[None]: # noqa: ARG001
18
+ def file_lock(file_path: Path, exclusive: bool = True) -> Iterator[None]:
19
19
  """Context manager for cross-platform file locking."""
20
20
  lock_path = file_path.with_suffix(file_path.suffix + ".lock")
21
21
  lock_path.parent.mkdir(parents=True, exist_ok=True)
22
22
 
23
23
  with lock_path.open("a+", encoding="utf-8") as handle:
24
24
  _ensure_lockfile_content(handle)
25
- _acquire_lock(handle)
25
+ _acquire_lock(handle, exclusive=exclusive)
26
26
  try:
27
27
  yield
28
28
  finally:
@@ -37,13 +37,13 @@ def _ensure_lockfile_content(handle: TextIO) -> None:
37
37
  handle.seek(0)
38
38
 
39
39
 
40
- def _acquire_lock(handle: TextIO) -> None:
40
+ def _acquire_lock(handle: TextIO, *, exclusive: bool = True) -> None:
41
41
  if os.name == "nt": # pragma: no cover - exercised on Windows
42
42
  handle.seek(0)
43
- msvcrt.locking(handle.fileno(), msvcrt.LK_LOCK, 1)
43
+ msvcrt.locking(handle.fileno(), msvcrt.LK_RLCK if not exclusive else msvcrt.LK_LOCK, 1)
44
44
  return
45
45
 
46
- fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
46
+ fcntl.flock(handle.fileno(), fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH)
47
47
 
48
48
 
49
49
  def _release_lock(handle: TextIO) -> None:
@@ -8,8 +8,10 @@ handling, and server lifecycle.
8
8
  import asyncio
9
9
  from collections.abc import Sequence
10
10
  import inspect
11
+ import keyword
11
12
  import os
12
13
  from pathlib import Path
14
+ import re
13
15
  from typing import Any
14
16
 
15
17
  import structlog
@@ -105,13 +107,50 @@ def _build_tool_signature(parameters: tuple[MCPToolParameter, ...]) -> inspect.S
105
107
  By setting __signature__ with explicit parameters, FastMCP generates the
106
108
  correct schema and clients can send flat argument dicts.
107
109
  """
110
+ signature, _ = _build_tool_signature_with_aliases(parameters)
111
+ return signature
112
+
113
+
114
+ def _to_safe_signature_name(name: str) -> str:
115
+ """Return a valid Python identifier for a tool parameter name."""
116
+ if name.isidentifier() and not keyword.iskeyword(name):
117
+ return name
118
+
119
+ # Replace invalid characters with underscore and avoid starting with a digit.
120
+ sanitized = re.sub(r"[^0-9a-zA-Z_]", "_", name)
121
+ sanitized = re.sub(r"_+", "_", sanitized).strip("_")
122
+ if not sanitized or sanitized[0].isdigit():
123
+ sanitized = f"_{sanitized or 'param'}"
124
+
125
+ if keyword.iskeyword(sanitized):
126
+ sanitized = f"_{sanitized}"
127
+
128
+ return sanitized
129
+
130
+
131
+ def _build_tool_signature_with_aliases(
132
+ parameters: tuple[MCPToolParameter, ...],
133
+ ) -> tuple[inspect.Signature, dict[str, str]]:
134
+ """Build signature plus map from schema args to original MCP parameter names."""
135
+
108
136
  sig_params = []
137
+ alias_counts: dict[str, int] = {}
138
+ alias_to_original: dict[str, str] = {}
139
+
109
140
  for p in parameters:
141
+ parameter_name = _to_safe_signature_name(p.name)
142
+ alias_count = alias_counts.get(parameter_name, 0) + 1
143
+ alias_counts[parameter_name] = alias_count
144
+ if alias_count > 1:
145
+ parameter_name = f"{parameter_name}_{alias_count}"
146
+
147
+ alias_to_original[parameter_name] = p.name
148
+
110
149
  python_type = _TOOL_TYPE_MAP.get(p.type, Any)
111
150
  if p.required:
112
151
  sig_params.append(
113
152
  inspect.Parameter(
114
- name=p.name,
153
+ name=parameter_name,
115
154
  kind=inspect.Parameter.KEYWORD_ONLY,
116
155
  annotation=python_type,
117
156
  )
@@ -120,13 +159,14 @@ def _build_tool_signature(parameters: tuple[MCPToolParameter, ...]) -> inspect.S
120
159
  default = p.default if p.default is not None else None
121
160
  sig_params.append(
122
161
  inspect.Parameter(
123
- name=p.name,
162
+ name=parameter_name,
124
163
  kind=inspect.Parameter.KEYWORD_ONLY,
125
164
  default=default,
126
165
  annotation=python_type | None,
127
166
  )
128
167
  )
129
- return inspect.Signature(parameters=sig_params)
168
+
169
+ return inspect.Signature(parameters=sig_params), alias_to_original
130
170
 
131
171
 
132
172
  _PROJECT_ROOT_MARKERS = (
@@ -200,11 +240,13 @@ def _project_dir_from_artifact(artifact: str) -> str | None:
200
240
  from pathlib import Path
201
241
  import re
202
242
 
203
- # Match quoted paths (spaces allowed) or unquoted paths (no spaces).
243
+ # Match quoted paths (spaces allowed) and unquoted paths.
204
244
  # Examples: Write: /foo/bar.py | File: "/path with spaces/bar.py"
205
245
  write_matches: list[str] = []
206
- for m in re.finditer(r'(?:Write|Edit|File): (?:"([^"]+)"|(/[^\s]+))', artifact):
207
- write_matches.append(m.group(1) or m.group(2))
246
+ for m in re.finditer(r'(?:Write|Edit|File): (?:"([^"]+)"|(.+))', artifact):
247
+ path_candidate = m.group(1) or m.group(2)
248
+ if path_candidate:
249
+ write_matches.append(path_candidate.strip())
208
250
  for path_str in write_matches:
209
251
  candidate = Path(path_str).parent
210
252
  for _ in range(10):
@@ -529,7 +571,18 @@ class MCPServerAdapter:
529
571
  and isinstance(kwargs["kwargs"], dict)
530
572
  ):
531
573
  kwargs = kwargs["kwargs"]
532
- result = await h.handle(kwargs)
574
+
575
+ _, alias_to_original = _build_tool_signature_with_aliases(
576
+ h.definition.parameters,
577
+ )
578
+ normalized_kwargs: dict[str, Any] = {}
579
+ for alias_key, original_key in alias_to_original.items():
580
+ if alias_key in kwargs:
581
+ normalized_kwargs[original_key] = kwargs[alias_key]
582
+ for key, value in kwargs.items():
583
+ normalized_kwargs.setdefault(key, value)
584
+
585
+ result = await h.handle(normalized_kwargs)
533
586
  if result.is_ok:
534
587
  # Convert MCPToolResult to FastMCP format
535
588
  tool_result = result.value
@@ -2059,6 +2059,7 @@ class MCPToolProvider:
2059
2059
 
2060
2060
  try:
2061
2061
  # Retry transient failures with bounded backoff
2062
+ # Use retry_async for retries on transient failures
2062
2063
  result = await self._call_with_retry(
2063
2064
  tool_info=tool_info,
2064
2065
  arguments=arguments or {},
@@ -2090,7 +2091,7 @@ class MCPToolProvider:
2090
2091
  ) -> Result[MCPToolResult, MCPToolError]:
2091
2092
  """Call tool with retry logic for transient failures.
2092
2093
 
2093
- Uses internal exponential backoff retries on:
2094
+ Uses retry_async for exponential backoff retries on:
2094
2095
  - Connection errors
2095
2096
  - Timeout errors (if marked retriable)
2096
2097
  - Other transient MCPClientErrors
@@ -160,6 +160,18 @@ class LiteLLMAdapter:
160
160
  if configured_api_key:
161
161
  return configured_api_key
162
162
 
163
+ # Unknown/custom models may still be routed through OpenRouter via credentials.
164
+ provider_name = self._extract_provider(model)
165
+ if provider_name not in {"openrouter", "openai", "anthropic", "google"}:
166
+ credentials = self._load_credentials_config()
167
+ configured = (
168
+ credentials.providers.get("openrouter") if credentials is not None else None
169
+ )
170
+ if configured is not None:
171
+ configured_api_key = self._normalize_api_key(configured.api_key)
172
+ if configured_api_key:
173
+ return configured_api_key
174
+
163
175
  # Default to OpenRouter for unknown models
164
176
  return self._normalize_api_key(os.environ.get("OPENROUTER_API_KEY"))
165
177
 
@@ -0,0 +1,45 @@
1
+ """Tests for interactive prompt helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from unittest.mock import AsyncMock, MagicMock, patch
7
+
8
+ import pytest
9
+
10
+ from ouroboros.cli.formatters.prompting import multiline_prompt_async
11
+
12
+
13
+ @pytest.mark.asyncio
14
+ async def test_multiline_prompt_async_patches_stdout_and_stderr() -> None:
15
+ """The shared prompt helper should proxy both stdout and stderr during input."""
16
+ session = MagicMock()
17
+ session.prompt_async = AsyncMock()
18
+
19
+ async def fake_prompt_async() -> str:
20
+ assert sys.stdout is not sys.__stdout__
21
+ assert sys.stderr is not sys.__stderr__
22
+ return "line 1\nline 2"
23
+
24
+ session.prompt_async.side_effect = fake_prompt_async
25
+
26
+ with (
27
+ patch(
28
+ "ouroboros.cli.formatters.prompting.PromptSession", return_value=session
29
+ ) as mock_session,
30
+ patch("ouroboros.cli.formatters.prompting.console.print"),
31
+ ):
32
+ result = await multiline_prompt_async("Prompt here")
33
+
34
+ assert result == "line 1\nline 2"
35
+ session.prompt_async.assert_awaited_once()
36
+
37
+ kwargs = mock_session.call_args.kwargs
38
+ assert kwargs["message"] == "> "
39
+ assert kwargs["multiline"] is True
40
+ assert kwargs["prompt_continuation"] == " "
41
+
42
+ key_bindings = kwargs["key_bindings"]
43
+ bound_keys = {tuple(binding.keys) for binding in key_bindings.bindings}
44
+ assert ("c-j",) in bound_keys
45
+ assert ("c-m",) in bound_keys
@@ -34,3 +34,19 @@ def test_load_env_file_does_not_override_existing_values(
34
34
  _load_env_file(env_file)
35
35
 
36
36
  assert os.environ["FIRST"] == "existing"
37
+
38
+
39
+ def test_load_env_file_skips_template_placeholders(tmp_path: Path, monkeypatch) -> None:
40
+ """Template placeholders should not block later env values from loading."""
41
+ repo_env = tmp_path / "repo.env"
42
+ home_env = tmp_path / "home.env"
43
+
44
+ repo_env.write_text("OPENROUTER_API_KEY=YOUR_OPENROUTER_API_KEY")
45
+ home_env.write_text("OPENROUTER_API_KEY=real-key")
46
+
47
+ monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
48
+
49
+ _load_env_file(repo_env)
50
+ _load_env_file(home_env)
51
+
52
+ assert os.environ["OPENROUTER_API_KEY"] == "real-key"
@@ -0,0 +1,52 @@
1
+ """Tests for stdlib-backed file locking."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from unittest.mock import MagicMock
7
+
8
+ import ouroboros.core.file_lock as file_lock_module
9
+ from ouroboros.core.file_lock import _acquire_lock, _release_lock, file_lock
10
+
11
+
12
+ def test_file_lock_creates_lockfile(tmp_path: Path) -> None:
13
+ target = tmp_path / "state.json"
14
+ target.write_text("{}")
15
+
16
+ with file_lock(target):
17
+ lock_path = target.with_suffix(".json.lock")
18
+ assert lock_path.exists()
19
+ assert lock_path.read_text() == "0"
20
+
21
+
22
+ def test_file_lock_exclusive_false_acquires_shared_lock(tmp_path: Path) -> None:
23
+ """Shared (non-exclusive) locks should allow concurrent readers."""
24
+ target = tmp_path / "data.json"
25
+ target.write_text("{}")
26
+
27
+ with file_lock(target, exclusive=False):
28
+ lock_path = target.with_suffix(".json.lock")
29
+ assert lock_path.exists()
30
+ # A second shared lock on the same file should not block
31
+ with file_lock(target, exclusive=False):
32
+ assert lock_path.exists()
33
+
34
+
35
+ def test_file_lock_windows_shared_uses_read_lock_mode(monkeypatch, tmp_path: Path) -> None:
36
+ """On Windows, non-exclusive lock requests should use a shared/read mode."""
37
+ target = tmp_path / "shared.json"
38
+ target.write_text("{}")
39
+ with target.open("a+", encoding="utf-8") as handle:
40
+ fd = handle.fileno()
41
+ mock_msvcrt = MagicMock()
42
+ mock_msvcrt.LK_LOCK = 1
43
+ mock_msvcrt.LK_RLCK = 2
44
+ mock_msvcrt.LK_UNLCK = 3
45
+ monkeypatch.setattr(file_lock_module, "msvcrt", mock_msvcrt, raising=False)
46
+ monkeypatch.setattr(file_lock_module.os, "name", "nt")
47
+
48
+ _acquire_lock(handle, exclusive=False)
49
+ _release_lock(handle)
50
+
51
+ mock_msvcrt.locking.assert_any_call(fd, mock_msvcrt.LK_RLCK, 1)
52
+ mock_msvcrt.locking.assert_any_call(fd, mock_msvcrt.LK_UNLCK, 1)
@@ -11,6 +11,7 @@ from ouroboros.mcp.errors import MCPResourceNotFoundError, MCPServerError
11
11
  from ouroboros.mcp.server.adapter import (
12
12
  VALID_TRANSPORTS,
13
13
  MCPServerAdapter,
14
+ _build_tool_signature_with_aliases,
14
15
  _extract_feedback_metadata_from_artifact,
15
16
  _project_dir_from_artifact,
16
17
  _project_dir_from_seed,
@@ -119,6 +120,34 @@ class TestMCPServerAdapter:
119
120
 
120
121
  assert _project_dir_from_artifact(artifact) == str(project_dir)
121
122
 
123
+ def test_project_dir_from_artifact_handles_spaces_in_paths(self, tmp_path) -> None:
124
+ """Artifact extraction should detect spaced file paths."""
125
+ project_dir = tmp_path / "my project"
126
+ nested_dir = project_dir / "src" / "components"
127
+ nested_dir.mkdir(parents=True)
128
+ (project_dir / "pyproject.toml").write_text("[build-system]")
129
+
130
+ artifact = f"Edit: {nested_dir / 'app.tsx'}"
131
+
132
+ assert _project_dir_from_artifact(artifact) == str(project_dir)
133
+
134
+ def test_build_tool_signature_sanitizes_non_identifier_parameter_names(self) -> None:
135
+ """Invalid MCP parameter names are sanitized to valid Python signatures."""
136
+ parameters = (
137
+ MCPToolParameter(name="file-path", type=ToolInputType.STRING),
138
+ MCPToolParameter(name="max.tokens", type=ToolInputType.INTEGER),
139
+ MCPToolParameter(name="class", type=ToolInputType.BOOLEAN),
140
+ )
141
+
142
+ signature, aliases = _build_tool_signature_with_aliases(parameters)
143
+ names = tuple(param.name for param in signature.parameters.values())
144
+ assert names == ("file_path", "max_tokens", "_class")
145
+ assert aliases == {
146
+ "file_path": "file-path",
147
+ "max_tokens": "max.tokens",
148
+ "_class": "class",
149
+ }
150
+
122
151
  def test_extract_feedback_metadata_from_artifact_parses_structured_warning(self) -> None:
123
152
  """Execution artifacts should expose structured evaluation feedback metadata."""
124
153
  artifact = """
@@ -128,6 +128,26 @@ class TestLiteLLMAdapterGetApiKey:
128
128
 
129
129
  assert result == "or-key"
130
130
 
131
+ def test_unknown_model_uses_openrouter_credentials_fallback(self) -> None:
132
+ """Unknown models can resolve credentials from the openrouter provider."""
133
+ adapter = LiteLLMAdapter()
134
+ credentials = CredentialsConfig(
135
+ providers={
136
+ "openrouter": ProviderCredentials(
137
+ api_key="cred-openrouter-key",
138
+ base_url="https://openrouter.example/v1",
139
+ ),
140
+ }
141
+ )
142
+
143
+ with (
144
+ patch.dict("os.environ", {}, clear=True),
145
+ patch.object(adapter, "_load_credentials_config", return_value=credentials),
146
+ ):
147
+ result = adapter._get_api_key("acme/gpt-4-custom")
148
+
149
+ assert result == "cred-openrouter-key"
150
+
131
151
  def test_missing_env_var_returns_none(self) -> None:
132
152
  """Returns None if no environment variable is set."""
133
153
  adapter = LiteLLMAdapter()