ouroboros-ai 0.26.6.dev2__tar.gz → 0.26.7.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 (577) hide show
  1. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.claude-plugin/marketplace.json +1 -1
  2. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.claude-plugin/plugin.json +1 -1
  3. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/PKG-INFO +1 -1
  4. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/setup/SKILL.md +1 -1
  5. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/_version.py +2 -2
  6. ouroboros_ai-0.26.7.dev2/src/ouroboros/core/json_utils.py +93 -0
  7. ouroboros_ai-0.26.7.dev2/src/ouroboros/evaluation/json_utils.py +5 -0
  8. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/evaluation_handlers.py +4 -2
  9. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/claude_code_adapter.py +123 -7
  10. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_json_utils.py +48 -0
  11. ouroboros_ai-0.26.7.dev2/tests/unit/mcp/tools/test_evaluation_handler.py +148 -0
  12. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/providers/test_claude_code_adapter.py +136 -2
  13. ouroboros_ai-0.26.6.dev2/src/ouroboros/evaluation/json_utils.py +0 -79
  14. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.claude/settings.json +0 -0
  15. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.claude-plugin/.mcp.json +0 -0
  16. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.env.example +0 -0
  17. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  18. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  19. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  20. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  21. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/workflows/dev-publish.yml +0 -0
  22. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/workflows/lint.yml +0 -0
  23. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/workflows/release.yml +0 -0
  24. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.github/workflows/test.yml +0 -0
  25. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.gitignore +0 -0
  26. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.mcp.json +0 -0
  27. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.ouroboros/mechanical.toml +0 -0
  28. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.pre-commit-config.yaml +0 -0
  29. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/.python-version +0 -0
  30. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/CHANGELOG.md +0 -0
  31. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/CLAUDE.md +0 -0
  32. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/CODE_OF_CONDUCT.md +0 -0
  33. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/CONTRIBUTING.md +0 -0
  34. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/HANDOFF.md +0 -0
  35. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/LICENSE +0 -0
  36. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/README.ko.md +0 -0
  37. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/README.md +0 -0
  38. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/SECURITY.md +0 -0
  39. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/UNINSTALL.md +0 -0
  40. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/cancel.md +0 -0
  41. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/evaluate.md +0 -0
  42. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/evolve.md +0 -0
  43. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/help.md +0 -0
  44. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/interview.md +0 -0
  45. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/ralph.md +0 -0
  46. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/run.md +0 -0
  47. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/seed.md +0 -0
  48. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/setup.md +0 -0
  49. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/status.md +0 -0
  50. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/tutorial.md +0 -0
  51. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/unstuck.md +0 -0
  52. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/commands/welcome.md +0 -0
  53. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/.gitignore +0 -0
  54. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/Cargo.lock +0 -0
  55. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/Cargo.toml +0 -0
  56. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/README.md +0 -0
  57. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/db.rs +0 -0
  58. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/main.rs +0 -0
  59. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/mock.rs +0 -0
  60. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/state.rs +0 -0
  61. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/views/dashboard.rs +0 -0
  62. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/views/execution.rs +0 -0
  63. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/views/lineage.rs +0 -0
  64. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/views/logs.rs +0 -0
  65. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/views/mod.rs +0 -0
  66. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/crates/ouroboros-tui/src/views/session_selector.rs +0 -0
  67. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/README.md +0 -0
  68. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/api/README.md +0 -0
  69. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/api/core.md +0 -0
  70. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/api/mcp.md +0 -0
  71. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/architecture.md +0 -0
  72. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/cli-reference.md +0 -0
  73. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/config-reference.md +0 -0
  74. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/contributing/architecture-overview.md +0 -0
  75. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/contributing/findings-registry.md +0 -0
  76. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/contributing/issue-quality-policy.md +0 -0
  77. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/contributing/key-patterns.md +0 -0
  78. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/contributing/testing-guide.md +0 -0
  79. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/examples/mcp-config.yaml +0 -0
  80. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/getting-started.md +0 -0
  81. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/guides/evaluation-pipeline.md +0 -0
  82. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/guides/evolution-loop.md +0 -0
  83. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/guides/issue-176-subagent-mcp-inheritance.md +0 -0
  84. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/guides/seed-authoring.md +0 -0
  85. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/guides/tui-usage.md +0 -0
  86. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/images/PLACEHOLDER_README.md +0 -0
  87. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/images/ouroboros.png +0 -0
  88. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/platform-support.md +0 -0
  89. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/runtime-capability-matrix.md +0 -0
  90. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/runtime-guides/claude-code.md +0 -0
  91. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/docs/runtime-guides/codex.md +0 -0
  92. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/coordinator_test_seed.yaml +0 -0
  93. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/dummy_seed.yaml +0 -0
  94. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/parallel_subac_test_seed.yaml +0 -0
  95. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/subac_test_seed.yaml +0 -0
  96. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/task_manager/README.md +0 -0
  97. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/task_manager/__init__.py +0 -0
  98. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/task_manager/__main__.py +0 -0
  99. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/task_manager/cli.py +0 -0
  100. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/task_manager/models.py +0 -0
  101. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/task_manager/storage.py +0 -0
  102. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/examples/test_display.py +0 -0
  103. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/hooks/hooks.json +0 -0
  104. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/llms-full.txt +0 -0
  105. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/llms.txt +0 -0
  106. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/project-context.md +0 -0
  107. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/pyproject.toml +0 -0
  108. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/drift-monitor.py +0 -0
  109. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/install.sh +0 -0
  110. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/keyword-detector.py +0 -0
  111. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/mcp-serve.sh +0 -0
  112. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/ralph-rewind.py +0 -0
  113. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/ralph.py +0 -0
  114. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/ralph.sh +0 -0
  115. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/session-start.py +0 -0
  116. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/sync-plugin-version.py +0 -0
  117. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/scripts/version-check.py +0 -0
  118. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/brownfield/SKILL.md +0 -0
  119. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/cancel/SKILL.md +0 -0
  120. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/evaluate/SKILL.md +0 -0
  121. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/evolve/SKILL.md +0 -0
  122. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/help/SKILL.md +0 -0
  123. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/interview/SKILL.md +0 -0
  124. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/pm/SKILL.md +0 -0
  125. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/qa/SKILL.md +0 -0
  126. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/ralph/SKILL.md +0 -0
  127. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/run/SKILL.md +0 -0
  128. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/seed/SKILL.md +0 -0
  129. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/status/SKILL.md +0 -0
  130. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/tutorial/SKILL.md +0 -0
  131. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/unstuck/SKILL.md +0 -0
  132. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/update/SKILL.md +0 -0
  133. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/skills/welcome/SKILL.md +0 -0
  134. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/__init__.py +0 -0
  135. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/__main__.py +0 -0
  136. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/__init__.py +0 -0
  137. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/advocate.md +0 -0
  138. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/analysis-agent.md +0 -0
  139. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/architect.md +0 -0
  140. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/breadth-keeper.md +0 -0
  141. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/code-executor.md +0 -0
  142. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/codebase-explorer.md +0 -0
  143. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/consensus-reviewer.md +0 -0
  144. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/contrarian.md +0 -0
  145. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/evaluator.md +0 -0
  146. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/hacker.md +0 -0
  147. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/judge.md +0 -0
  148. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/loader.py +0 -0
  149. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/ontologist.md +0 -0
  150. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/ontology-analyst.md +0 -0
  151. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/qa-judge.md +0 -0
  152. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/research-agent.md +0 -0
  153. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/researcher.md +0 -0
  154. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/seed-architect.md +0 -0
  155. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/seed-closer.md +0 -0
  156. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/semantic-evaluator.md +0 -0
  157. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/simplifier.md +0 -0
  158. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/agents/socratic-interviewer.md +0 -0
  159. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/__init__.py +0 -0
  160. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/ambiguity.py +0 -0
  161. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/brownfield.py +0 -0
  162. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/explore.py +0 -0
  163. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/interview.py +0 -0
  164. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/pm_completion.py +0 -0
  165. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/pm_document.py +0 -0
  166. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/pm_interview.py +0 -0
  167. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/pm_seed.py +0 -0
  168. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/question_classifier.py +0 -0
  169. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/bigbang/seed_generator.py +0 -0
  170. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/__init__.py +0 -0
  171. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/__init__.py +0 -0
  172. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/cancel.py +0 -0
  173. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/config.py +0 -0
  174. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/init.py +0 -0
  175. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/mcp.py +0 -0
  176. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/pm.py +0 -0
  177. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/run.py +0 -0
  178. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/setup.py +0 -0
  179. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/status.py +0 -0
  180. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/tui.py +0 -0
  181. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/commands/uninstall.py +0 -0
  182. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/formatters/__init__.py +0 -0
  183. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/formatters/panels.py +0 -0
  184. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/formatters/progress.py +0 -0
  185. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/formatters/prompting.py +0 -0
  186. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/formatters/tables.py +0 -0
  187. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/formatters/workflow_display.py +0 -0
  188. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/cli/main.py +0 -0
  189. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/codex/__init__.py +0 -0
  190. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/codex/artifacts.py +0 -0
  191. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/codex/ouroboros.md +0 -0
  192. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/codex_permissions.py +0 -0
  193. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/config/__init__.py +0 -0
  194. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/config/loader.py +0 -0
  195. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/config/models.py +0 -0
  196. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/__init__.py +0 -0
  197. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/ac_tree.py +0 -0
  198. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/context.py +0 -0
  199. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/errors.py +0 -0
  200. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/file_lock.py +0 -0
  201. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/git_workflow.py +0 -0
  202. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/initial_context.py +0 -0
  203. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/lineage.py +0 -0
  204. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/ontology_aspect.py +0 -0
  205. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/ontology_questions.py +0 -0
  206. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/project_paths.py +0 -0
  207. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/security.py +0 -0
  208. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/seed.py +0 -0
  209. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/text.py +0 -0
  210. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/types.py +0 -0
  211. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/core/worktree.py +0 -0
  212. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/__init__.py +0 -0
  213. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/artifact_collector.py +0 -0
  214. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/consensus.py +0 -0
  215. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/languages.py +0 -0
  216. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/mechanical.py +0 -0
  217. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/models.py +0 -0
  218. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/pipeline.py +0 -0
  219. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/semantic.py +0 -0
  220. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/trigger.py +0 -0
  221. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evaluation/verification_artifacts.py +0 -0
  222. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/events/__init__.py +0 -0
  223. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/events/base.py +0 -0
  224. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/events/decomposition.py +0 -0
  225. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/events/evaluation.py +0 -0
  226. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/events/interview.py +0 -0
  227. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/events/lineage.py +0 -0
  228. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/events/ontology.py +0 -0
  229. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evolution/__init__.py +0 -0
  230. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evolution/convergence.py +0 -0
  231. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evolution/loop.py +0 -0
  232. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evolution/projector.py +0 -0
  233. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evolution/reflect.py +0 -0
  234. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evolution/regression.py +0 -0
  235. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/evolution/wonder.py +0 -0
  236. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/execution/__init__.py +0 -0
  237. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/execution/atomicity.py +0 -0
  238. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/execution/decomposition.py +0 -0
  239. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/execution/double_diamond.py +0 -0
  240. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/execution/subagent.py +0 -0
  241. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/__init__.py +0 -0
  242. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/client/__init__.py +0 -0
  243. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/client/adapter.py +0 -0
  244. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/client/manager.py +0 -0
  245. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/client/protocol.py +0 -0
  246. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/errors.py +0 -0
  247. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/job_manager.py +0 -0
  248. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/resources/__init__.py +0 -0
  249. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/resources/handlers.py +0 -0
  250. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/server/__init__.py +0 -0
  251. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/server/adapter.py +0 -0
  252. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/server/protocol.py +0 -0
  253. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/server/security.py +0 -0
  254. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/__init__.py +0 -0
  255. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/authoring_handlers.py +0 -0
  256. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/brownfield_handler.py +0 -0
  257. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/dashboard.py +0 -0
  258. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/definitions.py +0 -0
  259. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/evolution_handlers.py +0 -0
  260. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/execution_handlers.py +0 -0
  261. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/job_handlers.py +0 -0
  262. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/pm_handler.py +0 -0
  263. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/qa.py +0 -0
  264. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/query_handlers.py +0 -0
  265. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/tools/registry.py +0 -0
  266. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/mcp/types.py +0 -0
  267. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/observability/__init__.py +0 -0
  268. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/observability/drift.py +0 -0
  269. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/observability/logging.py +0 -0
  270. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/observability/retrospective.py +0 -0
  271. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/__init__.py +0 -0
  272. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/adapter.py +0 -0
  273. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/codex_cli_runtime.py +0 -0
  274. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/command_dispatcher.py +0 -0
  275. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/coordinator.py +0 -0
  276. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/dependency_analyzer.py +0 -0
  277. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/events.py +0 -0
  278. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/execution_runtime_scope.py +0 -0
  279. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/execution_strategy.py +0 -0
  280. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/heartbeat.py +0 -0
  281. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/level_context.py +0 -0
  282. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/mcp_config.py +0 -0
  283. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/mcp_tools.py +0 -0
  284. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/parallel_executor.py +0 -0
  285. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/parallel_executor_models.py +0 -0
  286. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/runner.py +0 -0
  287. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/runtime_factory.py +0 -0
  288. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/runtime_message_projection.py +0 -0
  289. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/session.py +0 -0
  290. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/orchestrator/workflow_state.py +0 -0
  291. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/__init__.py +0 -0
  292. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/brownfield.py +0 -0
  293. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/checkpoint.py +0 -0
  294. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/event_store.py +0 -0
  295. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/migrations/__init__.py +0 -0
  296. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/migrations/runner.py +0 -0
  297. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/migrations/scripts/001_initial.sql +0 -0
  298. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/migrations/scripts/002_brownfield.sql +0 -0
  299. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/schema.py +0 -0
  300. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/persistence/uow.py +0 -0
  301. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/__init__.py +0 -0
  302. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/agents/__init__.py +0 -0
  303. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/agents/pool.py +0 -0
  304. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/agents/registry.py +0 -0
  305. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/orchestration/__init__.py +0 -0
  306. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/orchestration/router.py +0 -0
  307. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/orchestration/scheduler.py +0 -0
  308. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/skills/__init__.py +0 -0
  309. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/skills/docs.py +0 -0
  310. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/skills/executor.py +0 -0
  311. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/skills/keywords.py +0 -0
  312. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/plugin/skills/registry.py +0 -0
  313. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/pm/__init__.py +0 -0
  314. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/pm/handoff.py +0 -0
  315. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/pm/renderer.py +0 -0
  316. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/__init__.py +0 -0
  317. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/anthropic_adapter.py +0 -0
  318. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/base.py +0 -0
  319. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/codex_cli_adapter.py +0 -0
  320. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/codex_cli_stream.py +0 -0
  321. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/factory.py +0 -0
  322. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/providers/litellm_adapter.py +0 -0
  323. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/py.typed +0 -0
  324. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/resilience/__init__.py +0 -0
  325. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/resilience/lateral.py +0 -0
  326. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/resilience/stagnation.py +0 -0
  327. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/routing/__init__.py +0 -0
  328. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/routing/complexity.py +0 -0
  329. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/routing/downgrade.py +0 -0
  330. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/routing/escalation.py +0 -0
  331. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/routing/router.py +0 -0
  332. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/routing/tiers.py +0 -0
  333. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/secondary/__init__.py +0 -0
  334. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/secondary/scheduler.py +0 -0
  335. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/secondary/todo_registry.py +0 -0
  336. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/strategies/__init__.py +0 -0
  337. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/strategies/devil_advocate.py +0 -0
  338. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/__init__.py +0 -0
  339. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/app.py +0 -0
  340. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/components/__init__.py +0 -0
  341. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/components/agents_panel.py +0 -0
  342. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/components/event_log.py +0 -0
  343. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/components/progress.py +0 -0
  344. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/components/token_tracker.py +0 -0
  345. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/events.py +0 -0
  346. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/__init__.py +0 -0
  347. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/confirm_rewind.py +0 -0
  348. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/dashboard.py +0 -0
  349. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/dashboard_v2.py +0 -0
  350. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/dashboard_v3.py +0 -0
  351. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/debug.py +0 -0
  352. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/execution.py +0 -0
  353. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/hud_dashboard.py +0 -0
  354. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/lineage_detail.py +0 -0
  355. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/lineage_selector.py +0 -0
  356. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/logs.py +0 -0
  357. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/screens/session_selector.py +0 -0
  358. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/__init__.py +0 -0
  359. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/ac_progress.py +0 -0
  360. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/ac_tree.py +0 -0
  361. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/agent_activity.py +0 -0
  362. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/cost_tracker.py +0 -0
  363. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/drift_meter.py +0 -0
  364. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/lineage_tree.py +0 -0
  365. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/parallel_graph.py +0 -0
  366. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/tui/widgets/phase_progress.py +0 -0
  367. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/verification/__init__.py +0 -0
  368. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/verification/extractor.py +0 -0
  369. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/verification/models.py +0 -0
  370. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/src/ouroboros/verification/verifier.py +0 -0
  371. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/__init__.py +0 -0
  372. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/conftest.py +0 -0
  373. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/e2e/__init__.py +0 -0
  374. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/e2e/conftest.py +0 -0
  375. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/e2e/test_cli_commands.py +0 -0
  376. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/e2e/test_full_workflow.py +0 -0
  377. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/e2e/test_session_persistence.py +0 -0
  378. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/fixtures/test_atomicity_seed.yml +0 -0
  379. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/__init__.py +0 -0
  380. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/conftest.py +0 -0
  381. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/mcp/__init__.py +0 -0
  382. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/mcp/conftest.py +0 -0
  383. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/mcp/test_client_adapter.py +0 -0
  384. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/mcp/test_client_manager.py +0 -0
  385. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/mcp/test_server_adapter.py +0 -0
  386. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/plugin/test_orchestration.py +0 -0
  387. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/test_codex_cli_passthrough_smoke.py +0 -0
  388. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/test_codex_skill_fallback.py +0 -0
  389. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/test_codex_skill_smoke.py +0 -0
  390. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/integration/test_entry_point.py +0 -0
  391. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/__init__.py +0 -0
  392. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/agents/__init__.py +0 -0
  393. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/agents/test_loader.py +0 -0
  394. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/__init__.py +0 -0
  395. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_ambiguity.py +0 -0
  396. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_brownfield.py +0 -0
  397. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_classifier_context.py +0 -0
  398. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_decide_later_items.py +0 -0
  399. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_explore.py +0 -0
  400. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_interview.py +0 -0
  401. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_pm_completion.py +0 -0
  402. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_pm_document_generator.py +0 -0
  403. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_pm_document_writer.py +0 -0
  404. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_pm_interview.py +0 -0
  405. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_pm_interview_brownfield_db.py +0 -0
  406. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_pm_seed_ac12.py +0 -0
  407. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_pm_seed_save.py +0 -0
  408. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_question_classifier.py +0 -0
  409. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/bigbang/test_seed_generator.py +0 -0
  410. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/__init__.py +0 -0
  411. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/formatters/__init__.py +0 -0
  412. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/formatters/test_console.py +0 -0
  413. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/formatters/test_panels.py +0 -0
  414. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/formatters/test_progress.py +0 -0
  415. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/formatters/test_prompting.py +0 -0
  416. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/formatters/test_tables.py +0 -0
  417. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/formatters/test_workflow_display.py +0 -0
  418. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_cancel.py +0 -0
  419. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_config.py +0 -0
  420. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_init_pm_seed_detection.py +0 -0
  421. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_init_runtime.py +0 -0
  422. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_main.py +0 -0
  423. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_mcp_nested_guard.py +0 -0
  424. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_mcp_startup_cleanup.py +0 -0
  425. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm.py +0 -0
  426. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm_brownfield.py +0 -0
  427. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm_completion.py +0 -0
  428. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm_interactive_logging.py +0 -0
  429. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm_missing_litellm.py +0 -0
  430. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm_overwrite.py +0 -0
  431. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm_runtime_adapter.py +0 -0
  432. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_pm_select_repos.py +0 -0
  433. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_run_qa.py +0 -0
  434. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_setup.py +0 -0
  435. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/cli/test_uninstall.py +0 -0
  436. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/config/__init__.py +0 -0
  437. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/config/test_loader.py +0 -0
  438. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/config/test_models.py +0 -0
  439. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/__init__.py +0 -0
  440. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_ac_tree.py +0 -0
  441. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_context.py +0 -0
  442. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_errors.py +0 -0
  443. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_git_workflow.py +0 -0
  444. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_initial_context.py +0 -0
  445. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_lineage.py +0 -0
  446. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_ontology_aspect.py +0 -0
  447. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_ontology_questions.py +0 -0
  448. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_security.py +0 -0
  449. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_seed.py +0 -0
  450. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_types.py +0 -0
  451. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/core/test_worktree.py +0 -0
  452. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/__init__.py +0 -0
  453. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_consensus.py +0 -0
  454. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_languages.py +0 -0
  455. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_mechanical.py +0 -0
  456. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_models.py +0 -0
  457. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_semantic.py +0 -0
  458. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_trigger.py +0 -0
  459. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evaluation/test_verification_artifacts.py +0 -0
  460. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/events/__init__.py +0 -0
  461. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/events/test_base.py +0 -0
  462. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/events/test_decomposition_events.py +0 -0
  463. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/evolution/test_wonder_scope.py +0 -0
  464. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/execution/__init__.py +0 -0
  465. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/execution/test_atomicity.py +0 -0
  466. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/execution/test_decomposition.py +0 -0
  467. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/execution/test_double_diamond.py +0 -0
  468. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/execution/test_subagent_isolation.py +0 -0
  469. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/__init__.py +0 -0
  470. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/client/__init__.py +0 -0
  471. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/client/test_adapter.py +0 -0
  472. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/client/test_manager.py +0 -0
  473. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/conftest.py +0 -0
  474. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/server/__init__.py +0 -0
  475. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/server/test_adapter.py +0 -0
  476. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/server/test_security.py +0 -0
  477. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/test_errors.py +0 -0
  478. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/test_job_manager.py +0 -0
  479. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/test_types.py +0 -0
  480. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/__init__.py +0 -0
  481. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/conftest.py +0 -0
  482. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_brownfield_handler.py +0 -0
  483. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_definitions.py +0 -0
  484. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_pm_handler.py +0 -0
  485. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_pm_handler_generate.py +0 -0
  486. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_pm_handler_pending_reframe.py +0 -0
  487. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_qa_integration.py +0 -0
  488. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_qa_parser.py +0 -0
  489. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/mcp/tools/test_registry.py +0 -0
  490. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/observability/__init__.py +0 -0
  491. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/observability/test_drift.py +0 -0
  492. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/observability/test_logging.py +0 -0
  493. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/observability/test_retrospective.py +0 -0
  494. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/__init__.py +0 -0
  495. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_adapter.py +0 -0
  496. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_codex_cli_runtime.py +0 -0
  497. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_codex_recursion_guard.py +0 -0
  498. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_command_dispatcher.py +0 -0
  499. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_coordinator.py +0 -0
  500. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_dependency_analyzer.py +0 -0
  501. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_events.py +0 -0
  502. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_execution_runtime_scope.py +0 -0
  503. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_execution_strategy.py +0 -0
  504. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_inflight_cancellation.py +0 -0
  505. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_level_context.py +0 -0
  506. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_mcp_config.py +0 -0
  507. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_mcp_tools.py +0 -0
  508. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_parallel_executor.py +0 -0
  509. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_parallel_executor_retry_resume.py +0 -0
  510. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_runner.py +0 -0
  511. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_runner_cancellation.py +0 -0
  512. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_runtime_factory.py +0 -0
  513. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_runtime_message_projection.py +0 -0
  514. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_session.py +0 -0
  515. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/orchestrator/test_workflow_state.py +0 -0
  516. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/persistence/__init__.py +0 -0
  517. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/persistence/test_brownfield_store.py +0 -0
  518. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/persistence/test_checkpoint.py +0 -0
  519. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/persistence/test_event_store.py +0 -0
  520. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/persistence/test_schema.py +0 -0
  521. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/persistence/test_uow.py +0 -0
  522. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/__init__.py +0 -0
  523. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/agents/__init__.py +0 -0
  524. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/agents/test_registry.py +0 -0
  525. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/orchestration/__init__.py +0 -0
  526. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/orchestration/test_model_router.py +0 -0
  527. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/skills/__init__.py +0 -0
  528. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/skills/test_keywords.py +0 -0
  529. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/plugin/skills/test_registry.py +0 -0
  530. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/pm/__init__.py +0 -0
  531. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/pm/test_renderer.py +0 -0
  532. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/providers/__init__.py +0 -0
  533. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/providers/test_base.py +0 -0
  534. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/providers/test_codex_cli_adapter.py +0 -0
  535. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/providers/test_factory.py +0 -0
  536. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/providers/test_litellm_adapter.py +0 -0
  537. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/resilience/__init__.py +0 -0
  538. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/resilience/test_lateral.py +0 -0
  539. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/resilience/test_stagnation.py +0 -0
  540. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/routing/__init__.py +0 -0
  541. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/routing/test_complexity.py +0 -0
  542. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/routing/test_downgrade.py +0 -0
  543. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/routing/test_escalation.py +0 -0
  544. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/routing/test_router.py +0 -0
  545. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/routing/test_tiers.py +0 -0
  546. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/scripts/test_keyword_detector.py +0 -0
  547. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/scripts/test_version_check.py +0 -0
  548. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/secondary/__init__.py +0 -0
  549. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/secondary/test_scheduler.py +0 -0
  550. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/secondary/test_todo_registry.py +0 -0
  551. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_artifact_collector.py +0 -0
  552. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_codex_artifacts.py +0 -0
  553. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_convergence.py +0 -0
  554. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_dashboard.py +0 -0
  555. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_dependencies_configured.py +0 -0
  556. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_evolve_rewind.py +0 -0
  557. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_evolve_step.py +0 -0
  558. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_graceful_shutdown.py +0 -0
  559. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_main_entry_point.py +0 -0
  560. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_module_structure.py +0 -0
  561. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_project_initialization.py +0 -0
  562. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_projector_rewind.py +0 -0
  563. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_ralph_parser.py +0 -0
  564. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_ralph_rewind.py +0 -0
  565. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_regression.py +0 -0
  566. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_tooling_configuration.py +0 -0
  567. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/test_verification.py +0 -0
  568. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/__init__.py +0 -0
  569. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/test_app.py +0 -0
  570. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/test_cancelled_display.py +0 -0
  571. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/test_events.py +0 -0
  572. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/test_lineage_viewer.py +0 -0
  573. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/test_screens.py +0 -0
  574. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/test_session_selector_replay.py +0 -0
  575. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tests/unit/tui/test_widgets.py +0 -0
  576. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/tools/sync_github_project.py +0 -0
  577. {ouroboros_ai-0.26.6.dev2 → ouroboros_ai-0.26.7.dev2}/uv.lock +0 -0
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "ouroboros",
12
12
  "description": "Transform vague ideas into validated seed specifications through Socratic questioning and ontological analysis",
13
- "version": "0.26.5",
13
+ "version": "0.26.6",
14
14
  "author": {
15
15
  "name": "Q00",
16
16
  "email": "jqyu.lee@gmail.com"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ouroboros",
3
- "version": "0.26.5",
3
+ "version": "0.26.6",
4
4
  "description": "Self-improving AI workflow system. Crystallize requirements before execution with Socratic interview, ambiguity scoring, and 3-stage evaluation.",
5
5
  "author": {
6
6
  "name": "Q00",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ouroboros-ai
3
- Version: 0.26.6.dev2
3
+ Version: 0.26.7.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
@@ -246,7 +246,7 @@ A backup will be created: CLAUDE.md.bak
246
246
  **If "Preview first", show:**
247
247
  ````markdown
248
248
  <!-- ooo:START -->
249
- <!-- ooo:VERSION:0.26.5 -->
249
+ <!-- ooo:VERSION:0.26.6 -->
250
250
  # Ouroboros — Specification-First AI Development
251
251
 
252
252
  > Before telling AI what to build, define what should be built.
@@ -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.26.6.dev2'
22
- __version_tuple__ = version_tuple = (0, 26, 6, 'dev2')
21
+ __version__ = version = '0.26.7.dev2'
22
+ __version_tuple__ = version_tuple = (0, 26, 7, 'dev2')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -0,0 +1,93 @@
1
+ """Shared JSON extraction utilities for evaluation modules.
2
+
3
+ Provides a robust bracket-matching JSON extractor used by semantic,
4
+ consensus, and QA evaluation stages.
5
+ """
6
+
7
+ import json
8
+ import re
9
+
10
+
11
+ def extract_json_payload(text: str) -> str | None:
12
+ """Extract the first valid JSON object or array from text.
13
+
14
+ Tries each ``{`` or ``[`` position via bracket-depth counting and
15
+ validates with ``json.loads``. This handles LLM responses that
16
+ contain prose before the actual JSON payload.
17
+
18
+ Args:
19
+ text: Raw text potentially containing a JSON object or array
20
+
21
+ Returns:
22
+ Extracted JSON string, or None if no valid JSON is found
23
+ """
24
+ # Strip code fences first (```json ... ```)
25
+ fence_match = re.search(r"```(?:json)?\s*([\[{][\s\S]*?[}\]])\s*```", text)
26
+ if fence_match:
27
+ text = fence_match.group(1)
28
+
29
+ pos = 0
30
+ while True:
31
+ # Find the next { or [ opener
32
+ obj_start = text.find("{", pos)
33
+ arr_start = text.find("[", pos)
34
+
35
+ if obj_start == -1 and arr_start == -1:
36
+ return None
37
+
38
+ # Pick whichever comes first
39
+ if obj_start == -1:
40
+ start = arr_start
41
+ elif arr_start == -1:
42
+ start = obj_start
43
+ else:
44
+ start = min(obj_start, arr_start)
45
+
46
+ candidate = _bracket_extract(text, start)
47
+ if candidate is not None:
48
+ try:
49
+ json.loads(candidate)
50
+ return candidate
51
+ except (json.JSONDecodeError, ValueError):
52
+ pass
53
+
54
+ pos = start + 1
55
+
56
+
57
+ def _bracket_extract(text: str, start: int) -> str | None:
58
+ """Extract a bracket-balanced substring starting at *start*.
59
+
60
+ Supports both ``{}`` (objects) and ``[]`` (arrays). Returns the
61
+ substring ``text[start:end+1]`` where *end* is the position of
62
+ the matching closer, or ``None`` if brackets never balance.
63
+ """
64
+ open_char = text[start]
65
+ close_char = "}" if open_char == "{" else "]"
66
+ depth = 0
67
+ in_string = False
68
+ escape_next = False
69
+
70
+ for i, char in enumerate(text[start:], start=start):
71
+ if escape_next:
72
+ escape_next = False
73
+ continue
74
+
75
+ if char == "\\":
76
+ escape_next = True
77
+ continue
78
+
79
+ if char == '"' and not escape_next:
80
+ in_string = not in_string
81
+ continue
82
+
83
+ if in_string:
84
+ continue
85
+
86
+ if char == open_char:
87
+ depth += 1
88
+ elif char == close_char:
89
+ depth -= 1
90
+ if depth == 0:
91
+ return text[start : i + 1]
92
+
93
+ return None
@@ -0,0 +1,5 @@
1
+ """Backwards-compatible re-export. Canonical location: ouroboros.core.json_utils."""
2
+
3
+ from ouroboros.core.json_utils import extract_json_payload
4
+
5
+ __all__ = ["extract_json_payload"]
@@ -409,10 +409,12 @@ class EvaluateHandler:
409
409
  constraints=constraints,
410
410
  )
411
411
 
412
- # Use injected or create services
412
+ # Use injected or create services.
413
+ # Evaluation reads multiple spec files (one Read call per AC), so
414
+ # max_turns must be well above 1.
413
415
  llm_adapter = self.llm_adapter or create_llm_adapter(
414
416
  backend=self.llm_backend,
415
- max_turns=1,
417
+ max_turns=20,
416
418
  )
417
419
  working_dir_str = arguments.get("working_dir")
418
420
  working_dir = Path(working_dir_str).resolve() if working_dir_str else Path.cwd()
@@ -35,6 +35,7 @@ from pathlib import Path
35
35
  import structlog
36
36
 
37
37
  from ouroboros.core.errors import ProviderError
38
+ from ouroboros.core.json_utils import extract_json_payload
38
39
  from ouroboros.core.types import Result
39
40
  from ouroboros.providers.base import (
40
41
  CompletionConfig,
@@ -48,6 +49,7 @@ log = structlog.get_logger(__name__)
48
49
 
49
50
  # Retry configuration for transient API errors
50
51
  _MAX_RETRIES = 5
52
+ _MAX_JSON_RETRIES = 3 # Extra retries when response_format requires JSON but LLM returns prose
51
53
  _INITIAL_BACKOFF_SECONDS = 2.0 # Increased for custom CLI startup
52
54
  _RETRYABLE_ERROR_PATTERNS = (
53
55
  "concurrency",
@@ -244,13 +246,35 @@ class ClaudeCodeAdapter:
244
246
  # output. When callers request a schema, reinforce the requirement in the
245
247
  # prompt text and let downstream parsers extract JSON from the plain-text
246
248
  # response rather than depending on SDK-level structured_output.
247
- if config.response_format and config.response_format.get("type") == "json_schema":
248
- schema = config.response_format.get("json_schema", {})
249
- schema_instruction = (
250
- "Respond with ONLY a valid JSON object that matches this schema. "
251
- "Do not use markdown fences, headers, or explanatory text.\n\n"
252
- f"JSON schema:\n{json.dumps(schema, indent=2, sort_keys=True)}"
253
- )
249
+ requires_json = bool(
250
+ config.response_format
251
+ and config.response_format.get("type") in ("json_schema", "json_object")
252
+ )
253
+ if requires_json:
254
+ fmt_type = config.response_format.get("type")
255
+ if fmt_type == "json_schema":
256
+ schema = config.response_format.get("json_schema", {})
257
+ # Derive the expected top-level type from the schema so the
258
+ # prompt instruction matches the schema contract (object, array, etc.)
259
+ top_type = schema.get("type", "object")
260
+ if top_type == "array":
261
+ type_noun = "JSON array"
262
+ elif top_type == "object":
263
+ type_noun = "JSON object"
264
+ else:
265
+ # Primitive schemas (string, number, boolean, null)
266
+ type_noun = "JSON value"
267
+ schema_instruction = (
268
+ f"Respond with ONLY a valid {type_noun} that matches this schema. "
269
+ "Do not use markdown fences, headers, or explanatory text.\n\n"
270
+ f"JSON schema:\n{json.dumps(schema, indent=2, sort_keys=True)}"
271
+ )
272
+ else:
273
+ # json_object — no schema, but still steer toward JSON
274
+ schema_instruction = (
275
+ "Respond with ONLY a valid JSON object. "
276
+ "Do not use markdown fences, headers, or explanatory text."
277
+ )
254
278
  if system_prompt:
255
279
  system_prompt = f"{system_prompt}\n\n{schema_instruction}"
256
280
  else:
@@ -269,6 +293,98 @@ class ClaudeCodeAdapter:
269
293
  has_system_prompt=system_prompt is not None,
270
294
  )
271
295
 
296
+ result = await self._complete_with_transient_retry(prompt, config, system_prompt)
297
+
298
+ # JSON enforcement layer: if response_format requires JSON,
299
+ # normalize or retry until we get valid JSON.
300
+ if requires_json and result.is_ok:
301
+ result = await self._enforce_json(result, prompt, config, system_prompt)
302
+
303
+ return result
304
+
305
+ def _normalize_json_content(
306
+ self, result: Result[CompletionResponse, ProviderError]
307
+ ) -> Result[CompletionResponse, ProviderError] | None:
308
+ """Try to extract and normalize JSON from a successful result.
309
+
310
+ Returns:
311
+ Normalized result if JSON found, None if no valid JSON in content.
312
+ """
313
+ if result.is_err:
314
+ return result
315
+ extracted = extract_json_payload(result.value.content)
316
+ if extracted:
317
+ result.value.content = extracted
318
+ return result
319
+ return None
320
+
321
+ async def _enforce_json(
322
+ self,
323
+ result: Result[CompletionResponse, ProviderError],
324
+ prompt: str,
325
+ config: CompletionConfig,
326
+ system_prompt: str | None,
327
+ ) -> Result[CompletionResponse, ProviderError]:
328
+ """Normalize JSON content or retry until valid JSON is obtained.
329
+
330
+ If the response contains valid JSON (even wrapped in prose/fences),
331
+ extract and return just the JSON. If no valid JSON, retry up to
332
+ _MAX_JSON_RETRIES times. If all retries fail, return an error.
333
+ """
334
+ # Try to normalize the initial result
335
+ normalized = self._normalize_json_content(result)
336
+ if normalized is not None:
337
+ return normalized
338
+
339
+ log.warning(
340
+ "claude_code_adapter.json_not_found",
341
+ max_json_retries=_MAX_JSON_RETRIES,
342
+ response_preview=result.value.content[:120],
343
+ )
344
+
345
+ for json_attempt in range(1, _MAX_JSON_RETRIES + 1):
346
+ log.info(
347
+ "claude_code_adapter.json_retry",
348
+ attempt=json_attempt,
349
+ max_json_retries=_MAX_JSON_RETRIES,
350
+ )
351
+ result = await self._complete_with_transient_retry(prompt, config, system_prompt)
352
+ if result.is_err:
353
+ return result
354
+ normalized = self._normalize_json_content(result)
355
+ if normalized is not None:
356
+ return normalized
357
+
358
+ # All retries exhausted — return error instead of prose
359
+ log.error(
360
+ "claude_code_adapter.json_retries_exhausted",
361
+ max_json_retries=_MAX_JSON_RETRIES,
362
+ response_preview=result.value.content[:120] if result.is_ok else "N/A",
363
+ )
364
+ return Result.err(
365
+ ProviderError(
366
+ message=(
367
+ f"JSON format required but LLM returned prose after {_MAX_JSON_RETRIES} retries"
368
+ ),
369
+ details={
370
+ "last_response_preview": (
371
+ result.value.content[:200] if result.is_ok else "N/A"
372
+ ),
373
+ },
374
+ )
375
+ )
376
+
377
+ async def _complete_with_transient_retry(
378
+ self,
379
+ prompt: str,
380
+ config: CompletionConfig,
381
+ system_prompt: str | None,
382
+ ) -> Result[CompletionResponse, ProviderError]:
383
+ """Inner retry loop for transient API errors (rate limits, timeouts, etc.).
384
+
385
+ This handles infrastructure-level failures only. JSON format
386
+ enforcement is handled by the caller.
387
+ """
272
388
  last_error: ProviderError | None = None
273
389
 
274
390
  for attempt in range(_MAX_RETRIES):
@@ -99,3 +99,51 @@ class TestExtractJsonPayload:
99
99
  result = extract_json_payload(text)
100
100
  assert result is not None
101
101
  assert '"valid": true' in result
102
+
103
+
104
+ class TestExtractJsonArray:
105
+ """extract_json_payload must also handle top-level JSON arrays."""
106
+
107
+ def test_pure_array(self):
108
+ text = '[{"a": 1}, {"b": 2}]'
109
+ result = extract_json_payload(text)
110
+ assert result is not None
111
+ assert '"a": 1' in result
112
+ assert result.startswith("[")
113
+
114
+ def test_array_in_code_fence(self):
115
+ text = '```json\n[{"item": "value"}]\n```'
116
+ result = extract_json_payload(text)
117
+ assert result is not None
118
+ assert result.startswith("[")
119
+
120
+ def test_prose_before_array(self):
121
+ text = 'Here are the results:\n[{"score": 0.9}, {"score": 0.8}]'
122
+ result = extract_json_payload(text)
123
+ assert result is not None
124
+ assert result.startswith("[")
125
+ assert '"score": 0.9' in result
126
+
127
+ def test_object_before_array_returns_object(self):
128
+ """When both object and array exist, return whichever comes first."""
129
+ text = '{"first": true} [1, 2, 3]'
130
+ result = extract_json_payload(text)
131
+ assert result is not None
132
+ assert '"first": true' in result
133
+
134
+ def test_array_before_object_returns_array(self):
135
+ text = '[1, 2] {"second": true}'
136
+ result = extract_json_payload(text)
137
+ assert result is not None
138
+ assert result == "[1, 2]"
139
+
140
+ def test_empty_array(self):
141
+ text = "prefix [] suffix"
142
+ result = extract_json_payload(text)
143
+ assert result == "[]"
144
+
145
+ def test_nested_array(self):
146
+ text = "[[1, 2], [3, 4]]"
147
+ result = extract_json_payload(text)
148
+ assert result is not None
149
+ assert result == "[[1, 2], [3, 4]]"
@@ -0,0 +1,148 @@
1
+ """Tests for EvaluateHandler — adapter creation parameters (max_turns).
2
+
3
+ Regression coverage for the bug where ooo evaluate always fails with
4
+ ``error_max_turns`` or ``exit code 1`` when invoked inside an active Claude
5
+ Code session:
6
+
7
+ - Bug: ``max_turns=1`` caused the evaluator subprocess to hit the agentic
8
+ loop limit on the very first tool call (``Read`` to inspect a spec file).
9
+ Each AC check requires at least one file read, so ``max_turns=1`` was
10
+ never sufficient.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from unittest.mock import AsyncMock, MagicMock, patch
16
+
17
+ from ouroboros.core.types import Result
18
+ from ouroboros.evaluation.models import (
19
+ CheckResult,
20
+ CheckType,
21
+ EvaluationResult,
22
+ MechanicalResult,
23
+ SemanticResult,
24
+ )
25
+ from ouroboros.mcp.tools.evaluation_handlers import EvaluateHandler
26
+ from ouroboros.providers.base import CompletionResponse, UsageInfo
27
+
28
+ # ── Helpers ──────────────────────────────────────────────────────────────────
29
+
30
+ _MINIMAL_SEED = """\
31
+ goal: Verify the system works correctly.
32
+ acceptance_criteria:
33
+ - AC-01: Output exists
34
+ """
35
+
36
+ _BASE_ARGUMENTS: dict = {
37
+ "session_id": "test-exec-001",
38
+ "artifact": "stub evaluation artifact",
39
+ "artifact_type": "docs",
40
+ "seed_content": _MINIMAL_SEED, # goal present → skips EventStore DB lookup
41
+ "acceptance_criterion": None,
42
+ "working_dir": None,
43
+ "trigger_consensus": False,
44
+ }
45
+
46
+
47
+ def _make_mock_adapter() -> MagicMock:
48
+ """Return a mock LLMAdapter with a successful complete() response."""
49
+ adapter = MagicMock()
50
+ adapter.complete = AsyncMock(
51
+ return_value=Result.ok(
52
+ CompletionResponse(
53
+ content="{}",
54
+ model="test-model",
55
+ usage=UsageInfo(prompt_tokens=0, completion_tokens=0, total_tokens=0),
56
+ )
57
+ )
58
+ )
59
+ return adapter
60
+
61
+
62
+ def _make_approved_eval_result() -> EvaluationResult:
63
+ """Return a minimal approved EvaluationResult for pipeline mocking."""
64
+ mechanical = MechanicalResult(
65
+ passed=True,
66
+ checks=(
67
+ CheckResult(
68
+ check_type=CheckType.LINT,
69
+ passed=True,
70
+ message="skipped",
71
+ details={"skipped": True},
72
+ ),
73
+ ),
74
+ )
75
+ semantic = SemanticResult(
76
+ score=0.9,
77
+ ac_compliance=True,
78
+ goal_alignment=0.9,
79
+ drift_score=0.05,
80
+ uncertainty=0.1,
81
+ reasoning="All ACs verified.",
82
+ )
83
+ return EvaluationResult(
84
+ execution_id="test-exec-001",
85
+ final_approved=True,
86
+ stage1_result=mechanical,
87
+ stage2_result=semantic,
88
+ stage3_result=None,
89
+ )
90
+
91
+
92
+ def _patch_pipeline():
93
+ """Context manager: patch EvaluationPipeline to return an approved result."""
94
+ mock_pipeline = MagicMock()
95
+ mock_pipeline.evaluate = AsyncMock(return_value=Result.ok(_make_approved_eval_result()))
96
+ return patch(
97
+ "ouroboros.evaluation.EvaluationPipeline",
98
+ return_value=mock_pipeline,
99
+ )
100
+
101
+
102
+ # ── Tests ─────────────────────────────────────────────────────────────────────
103
+
104
+
105
+ class TestEvaluateHandlerAdapterCreation:
106
+ """Verify that the handler creates an adapter suited for headless evaluation."""
107
+
108
+ async def test_creates_adapter_with_sufficient_max_turns(self):
109
+ """Adapter must allow enough turns for the evaluator to read spec files.
110
+
111
+ Regression: max_turns=1 caused error_max_turns on the first tool call.
112
+ Evaluating N acceptance criteria requires at least N Read tool calls,
113
+ so max_turns must be well above 1.
114
+ """
115
+ captured: dict = {}
116
+
117
+ def _capture(**kwargs):
118
+ captured.update(kwargs)
119
+ return _make_mock_adapter()
120
+
121
+ handler = EvaluateHandler(llm_adapter=None)
122
+
123
+ with (
124
+ patch(
125
+ "ouroboros.mcp.tools.evaluation_handlers.create_llm_adapter",
126
+ side_effect=_capture,
127
+ ),
128
+ _patch_pipeline(),
129
+ ):
130
+ await handler.handle(_BASE_ARGUMENTS)
131
+
132
+ assert "max_turns" in captured, "create_llm_adapter was not called"
133
+ assert captured["max_turns"] >= 10, (
134
+ f"max_turns={captured['max_turns']} is too low — the evaluator needs "
135
+ "at least one turn per AC file read. Use max_turns >= 10."
136
+ )
137
+
138
+ async def test_injected_adapter_skips_create_llm_adapter(self):
139
+ """When an adapter is injected (e.g. in tests), create_llm_adapter is not called."""
140
+ handler = EvaluateHandler(llm_adapter=_make_mock_adapter())
141
+
142
+ with (
143
+ patch("ouroboros.mcp.tools.evaluation_handlers.create_llm_adapter") as mock_create,
144
+ _patch_pipeline(),
145
+ ):
146
+ await handler.handle(_BASE_ARGUMENTS)
147
+
148
+ mock_create.assert_not_called()
@@ -243,8 +243,9 @@ class TestExecuteSingleRequestSystemPrompt:
243
243
  },
244
244
  )
245
245
 
246
- mock_execute = AsyncMock()
247
- mock_execute.return_value = MagicMock(is_ok=True)
246
+ mock_response = MagicMock(is_ok=True, is_err=False)
247
+ mock_response.value.content = '{"score": 0.9}'
248
+ mock_execute = AsyncMock(return_value=mock_response)
248
249
  adapter._execute_single_request = mock_execute
249
250
 
250
251
  with patch.dict("sys.modules", {"claude_agent_sdk": MagicMock()}):
@@ -254,6 +255,139 @@ class TestExecuteSingleRequestSystemPrompt:
254
255
  assert "Respond with ONLY a valid JSON object" in prompt_arg
255
256
  assert '"score"' in prompt_arg
256
257
 
258
+ @pytest.mark.asyncio
259
+ async def test_json_retry_on_prose_response(self) -> None:
260
+ """When response_format requires JSON but LLM returns prose, adapter retries."""
261
+ adapter = ClaudeCodeAdapter()
262
+ messages = [Message(role=MessageRole.USER, content="Evaluate this")]
263
+ config = CompletionConfig(
264
+ model="claude-sonnet-4-6",
265
+ response_format={
266
+ "type": "json_schema",
267
+ "json_schema": {"type": "object", "properties": {"score": {"type": "number"}}},
268
+ },
269
+ )
270
+
271
+ prose_response = MagicMock(is_ok=True, is_err=False)
272
+ prose_response.value.content = "Let me verify the acceptance criteria..."
273
+
274
+ json_response = MagicMock(is_ok=True, is_err=False)
275
+ json_response.value.content = '{"score": 0.85}'
276
+
277
+ mock_execute = AsyncMock(side_effect=[prose_response, json_response])
278
+ adapter._execute_single_request = mock_execute
279
+
280
+ with patch.dict("sys.modules", {"claude_agent_sdk": MagicMock()}):
281
+ result = await adapter.complete(messages, config)
282
+
283
+ assert result.is_ok
284
+ assert result.value.content == '{"score": 0.85}'
285
+ assert mock_execute.call_count == 2
286
+
287
+ @pytest.mark.asyncio
288
+ async def test_json_retry_exhausted_returns_error(self) -> None:
289
+ """When all JSON retries fail, return a ProviderError, not prose."""
290
+ adapter = ClaudeCodeAdapter()
291
+ messages = [Message(role=MessageRole.USER, content="Evaluate this")]
292
+ config = CompletionConfig(
293
+ model="claude-sonnet-4-6",
294
+ response_format={
295
+ "type": "json_schema",
296
+ "json_schema": {"type": "object", "properties": {"score": {"type": "number"}}},
297
+ },
298
+ )
299
+
300
+ prose_response = MagicMock(is_ok=True, is_err=False)
301
+ prose_response.value.content = "I cannot produce JSON right now"
302
+
303
+ # 1 initial + 3 retries = 4 calls total
304
+ mock_execute = AsyncMock(return_value=prose_response)
305
+ adapter._execute_single_request = mock_execute
306
+
307
+ with patch.dict("sys.modules", {"claude_agent_sdk": MagicMock()}):
308
+ result = await adapter.complete(messages, config)
309
+
310
+ assert result.is_err
311
+ assert "JSON format required" in result.error.message
312
+ assert mock_execute.call_count == 4 # 1 initial + 3 retries
313
+
314
+ @pytest.mark.asyncio
315
+ async def test_json_extracted_from_prose_wrapped_response(self) -> None:
316
+ """When response contains valid JSON wrapped in prose, extract and normalize."""
317
+ adapter = ClaudeCodeAdapter()
318
+ messages = [Message(role=MessageRole.USER, content="Evaluate this")]
319
+ config = CompletionConfig(
320
+ model="claude-sonnet-4-6",
321
+ response_format={
322
+ "type": "json_schema",
323
+ "json_schema": {"type": "object", "properties": {"score": {"type": "number"}}},
324
+ },
325
+ )
326
+
327
+ mixed_response = MagicMock(is_ok=True, is_err=False)
328
+ mixed_response.value.content = 'Here is the result:\n{"score": 0.85}\nDone.'
329
+
330
+ mock_execute = AsyncMock(return_value=mixed_response)
331
+ adapter._execute_single_request = mock_execute
332
+
333
+ with patch.dict("sys.modules", {"claude_agent_sdk": MagicMock()}):
334
+ result = await adapter.complete(messages, config)
335
+
336
+ assert result.is_ok
337
+ assert result.value.content == '{"score": 0.85}'
338
+ assert mock_execute.call_count == 1 # No retry needed
339
+
340
+ @pytest.mark.asyncio
341
+ async def test_json_schema_array_gets_correct_prompt_steering(self) -> None:
342
+ """json_schema with top-level array should say 'JSON array', not 'JSON object'."""
343
+ adapter = ClaudeCodeAdapter()
344
+ messages = [Message(role=MessageRole.USER, content="List items")]
345
+ config = CompletionConfig(
346
+ model="claude-sonnet-4-6",
347
+ response_format={
348
+ "type": "json_schema",
349
+ "json_schema": {
350
+ "type": "array",
351
+ "items": {"type": "object", "properties": {"name": {"type": "string"}}},
352
+ },
353
+ },
354
+ )
355
+
356
+ mock_response = MagicMock(is_ok=True, is_err=False)
357
+ mock_response.value.content = '[{"name": "a"}]'
358
+ mock_execute = AsyncMock(return_value=mock_response)
359
+ adapter._execute_single_request = mock_execute
360
+
361
+ with patch.dict("sys.modules", {"claude_agent_sdk": MagicMock()}):
362
+ result = await adapter.complete(messages, config)
363
+
364
+ prompt_arg = mock_execute.call_args.args[0]
365
+ assert "JSON array" in prompt_arg
366
+ assert "JSON object" not in prompt_arg
367
+ assert result.is_ok
368
+ assert result.value.content == '[{"name": "a"}]'
369
+
370
+ @pytest.mark.asyncio
371
+ async def test_json_object_format_gets_prompt_steering(self) -> None:
372
+ """json_object response_format should also get prompt steering."""
373
+ adapter = ClaudeCodeAdapter()
374
+ messages = [Message(role=MessageRole.USER, content="Return data")]
375
+ config = CompletionConfig(
376
+ model="claude-sonnet-4-6",
377
+ response_format={"type": "json_object"},
378
+ )
379
+
380
+ mock_response = MagicMock(is_ok=True, is_err=False)
381
+ mock_response.value.content = '{"data": "value"}'
382
+ mock_execute = AsyncMock(return_value=mock_response)
383
+ adapter._execute_single_request = mock_execute
384
+
385
+ with patch.dict("sys.modules", {"claude_agent_sdk": MagicMock()}):
386
+ await adapter.complete(messages, config)
387
+
388
+ prompt_arg = mock_execute.call_args.args[0]
389
+ assert "Respond with ONLY a valid JSON object" in prompt_arg
390
+
257
391
  @pytest.mark.asyncio
258
392
  async def test_execute_single_request_omits_output_format(self) -> None:
259
393
  """SDK options should not include output_format for json_schema requests."""