ouroboros-ai 0.26.5.dev5__tar.gz → 0.26.5.dev7__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.
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/PKG-INFO +1 -1
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/pm/SKILL.md +5 -1
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/_version.py +2 -2
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/init.py +17 -7
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/pm.py +115 -12
- ouroboros_ai-0.26.5.dev7/src/ouroboros/core/initial_context.py +209 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/authoring_handlers.py +12 -2
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/pm_handler.py +13 -3
- ouroboros_ai-0.26.5.dev7/src/ouroboros/pm/handoff.py +18 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_init_pm_seed_detection.py +34 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_pm.py +25 -5
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_pm_completion.py +14 -4
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_pm_interactive_logging.py +22 -7
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_pm_overwrite.py +81 -1
- ouroboros_ai-0.26.5.dev7/tests/unit/cli/test_pm_runtime_adapter.py +226 -0
- ouroboros_ai-0.26.5.dev7/tests/unit/core/test_initial_context.py +117 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/test_definitions.py +46 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/test_pm_handler_generate.py +45 -4
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.claude/settings.json +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.claude-plugin/.mcp.json +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.claude-plugin/marketplace.json +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.claude-plugin/plugin.json +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.env.example +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/ISSUE_TEMPLATE/question.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/workflows/dev-publish.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/workflows/lint.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/workflows/release.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.github/workflows/test.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.gitignore +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.mcp.json +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.ouroboros/mechanical.toml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.pre-commit-config.yaml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/.python-version +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/CHANGELOG.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/CLAUDE.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/CODE_OF_CONDUCT.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/CONTRIBUTING.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/HANDOFF.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/LICENSE +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/README.ko.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/README.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/SECURITY.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/UNINSTALL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/cancel.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/evaluate.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/evolve.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/help.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/interview.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/ralph.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/run.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/seed.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/setup.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/status.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/tutorial.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/unstuck.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/commands/welcome.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/.gitignore +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/Cargo.lock +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/Cargo.toml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/README.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/db.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/main.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/mock.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/state.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/views/dashboard.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/views/execution.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/views/lineage.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/views/logs.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/views/mod.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/crates/ouroboros-tui/src/views/session_selector.rs +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/README.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/api/README.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/api/core.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/api/mcp.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/architecture.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/cli-reference.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/config-reference.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/contributing/architecture-overview.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/contributing/findings-registry.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/contributing/issue-quality-policy.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/contributing/key-patterns.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/contributing/testing-guide.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/examples/mcp-config.yaml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/getting-started.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/guides/evaluation-pipeline.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/guides/evolution-loop.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/guides/issue-176-subagent-mcp-inheritance.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/guides/seed-authoring.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/guides/tui-usage.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/images/PLACEHOLDER_README.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/images/ouroboros.png +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/platform-support.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/runtime-capability-matrix.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/runtime-guides/claude-code.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/docs/runtime-guides/codex.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/coordinator_test_seed.yaml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/dummy_seed.yaml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/parallel_subac_test_seed.yaml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/subac_test_seed.yaml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/task_manager/README.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/task_manager/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/task_manager/__main__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/task_manager/cli.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/task_manager/models.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/task_manager/storage.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/examples/test_display.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/hooks/hooks.json +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/llms-full.txt +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/llms.txt +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/project-context.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/pyproject.toml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/drift-monitor.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/install.sh +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/keyword-detector.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/mcp-serve.sh +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/ralph-rewind.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/ralph.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/ralph.sh +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/session-start.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/sync-plugin-version.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/scripts/version-check.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/brownfield/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/cancel/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/evaluate/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/evolve/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/help/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/interview/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/qa/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/ralph/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/run/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/seed/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/setup/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/status/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/tutorial/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/unstuck/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/update/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/skills/welcome/SKILL.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/__main__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/advocate.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/analysis-agent.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/architect.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/breadth-keeper.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/code-executor.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/codebase-explorer.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/consensus-reviewer.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/contrarian.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/evaluator.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/hacker.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/judge.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/loader.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/ontologist.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/ontology-analyst.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/qa-judge.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/research-agent.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/researcher.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/seed-architect.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/seed-closer.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/semantic-evaluator.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/simplifier.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/agents/socratic-interviewer.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/ambiguity.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/brownfield.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/explore.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/interview.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/pm_completion.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/pm_document.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/pm_interview.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/pm_seed.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/question_classifier.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/bigbang/seed_generator.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/cancel.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/config.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/mcp.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/run.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/setup.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/status.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/tui.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/commands/uninstall.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/formatters/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/formatters/panels.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/formatters/progress.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/formatters/prompting.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/formatters/tables.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/formatters/workflow_display.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/cli/main.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/codex/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/codex/artifacts.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/codex/ouroboros.md +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/codex_permissions.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/config/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/config/loader.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/config/models.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/ac_tree.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/context.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/errors.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/file_lock.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/git_workflow.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/lineage.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/ontology_aspect.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/ontology_questions.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/project_paths.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/security.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/seed.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/text.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/types.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/core/worktree.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/artifact_collector.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/consensus.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/json_utils.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/languages.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/mechanical.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/models.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/pipeline.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/semantic.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/trigger.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evaluation/verification_artifacts.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/events/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/events/base.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/events/decomposition.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/events/evaluation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/events/interview.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/events/lineage.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/events/ontology.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evolution/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evolution/convergence.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evolution/loop.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evolution/projector.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evolution/reflect.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evolution/regression.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/evolution/wonder.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/execution/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/execution/atomicity.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/execution/decomposition.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/execution/double_diamond.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/execution/subagent.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/client/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/client/adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/client/manager.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/client/protocol.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/errors.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/job_manager.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/resources/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/resources/handlers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/server/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/server/adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/server/protocol.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/server/security.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/brownfield_handler.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/dashboard.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/definitions.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/evaluation_handlers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/evolution_handlers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/execution_handlers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/job_handlers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/qa.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/query_handlers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/types.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/observability/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/observability/drift.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/observability/logging.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/observability/retrospective.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/codex_cli_runtime.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/command_dispatcher.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/coordinator.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/dependency_analyzer.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/events.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/execution_runtime_scope.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/execution_strategy.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/heartbeat.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/level_context.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/mcp_config.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/mcp_tools.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/parallel_executor.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/parallel_executor_models.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/runner.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/runtime_factory.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/runtime_message_projection.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/session.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/orchestrator/workflow_state.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/brownfield.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/checkpoint.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/event_store.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/migrations/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/migrations/runner.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/migrations/scripts/001_initial.sql +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/migrations/scripts/002_brownfield.sql +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/schema.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/persistence/uow.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/agents/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/agents/pool.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/agents/registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/orchestration/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/orchestration/router.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/orchestration/scheduler.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/skills/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/skills/docs.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/skills/executor.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/skills/keywords.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/plugin/skills/registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/pm/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/pm/renderer.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/anthropic_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/base.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/claude_code_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/codex_cli_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/codex_cli_stream.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/factory.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/providers/litellm_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/py.typed +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/resilience/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/resilience/lateral.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/resilience/stagnation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/routing/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/routing/complexity.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/routing/downgrade.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/routing/escalation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/routing/router.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/routing/tiers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/secondary/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/secondary/scheduler.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/secondary/todo_registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/strategies/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/strategies/devil_advocate.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/app.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/components/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/components/agents_panel.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/components/event_log.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/components/progress.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/components/token_tracker.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/events.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/confirm_rewind.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/dashboard.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/dashboard_v2.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/dashboard_v3.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/debug.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/execution.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/hud_dashboard.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/lineage_detail.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/lineage_selector.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/logs.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/screens/session_selector.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/ac_progress.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/ac_tree.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/agent_activity.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/cost_tracker.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/drift_meter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/lineage_tree.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/parallel_graph.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/tui/widgets/phase_progress.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/verification/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/verification/extractor.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/verification/models.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/verification/verifier.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/conftest.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/e2e/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/e2e/conftest.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/e2e/test_cli_commands.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/e2e/test_full_workflow.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/e2e/test_session_persistence.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/fixtures/test_atomicity_seed.yml +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/conftest.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/mcp/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/mcp/conftest.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/mcp/test_client_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/mcp/test_client_manager.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/mcp/test_server_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/plugin/test_orchestration.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/test_codex_cli_passthrough_smoke.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/test_codex_skill_fallback.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/test_codex_skill_smoke.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/integration/test_entry_point.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/agents/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/agents/test_loader.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_ambiguity.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_brownfield.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_classifier_context.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_decide_later_items.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_explore.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_interview.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_pm_completion.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_pm_document_generator.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_pm_document_writer.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_pm_interview.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_pm_interview_brownfield_db.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_pm_seed_ac12.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_pm_seed_save.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_question_classifier.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/bigbang/test_seed_generator.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/formatters/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/formatters/test_console.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/formatters/test_panels.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/formatters/test_progress.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/formatters/test_prompting.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/formatters/test_tables.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/formatters/test_workflow_display.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_cancel.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_config.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_init_runtime.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_main.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_mcp_nested_guard.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_mcp_startup_cleanup.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_pm_brownfield.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_pm_missing_litellm.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_pm_select_repos.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_run_qa.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_setup.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_uninstall.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/config/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/config/test_loader.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/config/test_models.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_ac_tree.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_context.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_errors.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_git_workflow.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_lineage.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_ontology_aspect.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_ontology_questions.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_security.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_seed.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_types.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/core/test_worktree.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_consensus.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_json_utils.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_languages.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_mechanical.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_models.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_semantic.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_trigger.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evaluation/test_verification_artifacts.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/events/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/events/test_base.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/events/test_decomposition_events.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/evolution/test_wonder_scope.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/execution/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/execution/test_atomicity.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/execution/test_decomposition.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/execution/test_double_diamond.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/execution/test_subagent_isolation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/client/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/client/test_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/client/test_manager.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/conftest.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/server/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/server/test_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/server/test_security.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/test_errors.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/test_job_manager.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/test_types.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/conftest.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/test_brownfield_handler.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/test_pm_handler.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/test_pm_handler_pending_reframe.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/test_qa_integration.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/mcp/tools/test_registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/observability/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/observability/test_drift.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/observability/test_logging.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/observability/test_retrospective.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_codex_cli_runtime.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_codex_recursion_guard.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_command_dispatcher.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_coordinator.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_dependency_analyzer.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_events.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_execution_runtime_scope.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_execution_strategy.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_inflight_cancellation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_level_context.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_mcp_config.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_mcp_tools.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_parallel_executor.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_parallel_executor_retry_resume.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_runner.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_runner_cancellation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_runtime_factory.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_runtime_message_projection.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_session.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/orchestrator/test_workflow_state.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/persistence/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/persistence/test_brownfield_store.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/persistence/test_checkpoint.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/persistence/test_event_store.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/persistence/test_schema.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/persistence/test_uow.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/agents/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/agents/test_registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/orchestration/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/orchestration/test_model_router.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/skills/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/skills/test_keywords.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/plugin/skills/test_registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/pm/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/pm/test_renderer.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/providers/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/providers/test_base.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/providers/test_claude_code_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/providers/test_codex_cli_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/providers/test_factory.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/providers/test_litellm_adapter.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/resilience/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/resilience/test_lateral.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/resilience/test_stagnation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/routing/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/routing/test_complexity.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/routing/test_downgrade.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/routing/test_escalation.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/routing/test_router.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/routing/test_tiers.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/scripts/test_keyword_detector.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/scripts/test_version_check.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/secondary/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/secondary/test_scheduler.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/secondary/test_todo_registry.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_artifact_collector.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_codex_artifacts.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_convergence.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_dashboard.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_dependencies_configured.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_evolve_rewind.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_evolve_step.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_graceful_shutdown.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_main_entry_point.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_module_structure.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_project_initialization.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_projector_rewind.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_ralph_parser.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_ralph_rewind.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_regression.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_tooling_configuration.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/test_verification.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/__init__.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/test_app.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/test_cancelled_display.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/test_events.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/test_lineage_viewer.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/test_screens.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/test_session_selector_replay.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/tui/test_widgets.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tools/sync_github_project.py +0 -0
- {ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/uv.lock +0 -0
|
@@ -120,6 +120,10 @@ Show the following to the user:
|
|
|
120
120
|
PM document saved: <meta.pm_path>
|
|
121
121
|
(Clipboard에 복사되었습니다)
|
|
122
122
|
|
|
123
|
+
PM seed handoff artifact: <meta.pm_seed_path or meta.seed_path>
|
|
124
|
+
This is not the runnable Seed yet.
|
|
125
|
+
|
|
123
126
|
Next step:
|
|
124
|
-
ooo interview <meta.
|
|
127
|
+
ooo interview <meta.pm_seed_path or meta.seed_path>
|
|
128
|
+
ooo seed
|
|
125
129
|
```
|
|
@@ -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.5.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 26, 5, '
|
|
21
|
+
__version__ = version = '0.26.5.dev7'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 26, 5, 'dev7')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -26,6 +26,12 @@ from ouroboros.cli.formatters import console
|
|
|
26
26
|
from ouroboros.cli.formatters.panels import print_error, print_info, print_success, print_warning
|
|
27
27
|
from ouroboros.cli.formatters.prompting import multiline_prompt_async
|
|
28
28
|
from ouroboros.config import get_clarification_model
|
|
29
|
+
from ouroboros.core.initial_context import (
|
|
30
|
+
load_pm_seed_as_context as _load_pm_seed_as_context_result,
|
|
31
|
+
)
|
|
32
|
+
from ouroboros.core.initial_context import (
|
|
33
|
+
resolve_initial_context_input,
|
|
34
|
+
)
|
|
29
35
|
from ouroboros.observability import LoggingConfig, configure_logging
|
|
30
36
|
from ouroboros.providers import create_llm_adapter
|
|
31
37
|
from ouroboros.providers.base import LLMAdapter
|
|
@@ -619,13 +625,10 @@ def _load_pm_seed_as_context(seed_path: Path) -> str:
|
|
|
619
625
|
Returns:
|
|
620
626
|
YAML-formatted string for use as dev interview initial_context.
|
|
621
627
|
"""
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
pm_seed = PMSeed.from_dict(data)
|
|
628
|
-
return pm_seed.to_initial_context()
|
|
628
|
+
result = _load_pm_seed_as_context_result(seed_path)
|
|
629
|
+
if result.is_err:
|
|
630
|
+
raise ValueError(str(result.error))
|
|
631
|
+
return result.value
|
|
629
632
|
|
|
630
633
|
|
|
631
634
|
@app.command()
|
|
@@ -752,6 +755,13 @@ def start(
|
|
|
752
755
|
|
|
753
756
|
context = asyncio.run(multiline_prompt_async("What would you like to build?"))
|
|
754
757
|
|
|
758
|
+
if context:
|
|
759
|
+
resolved_context = resolve_initial_context_input(context, cwd=Path.cwd())
|
|
760
|
+
if resolved_context.is_err:
|
|
761
|
+
print_error(str(resolved_context.error))
|
|
762
|
+
raise typer.Exit(code=1)
|
|
763
|
+
context = resolved_context.value
|
|
764
|
+
|
|
755
765
|
if not resume and not context:
|
|
756
766
|
print_error("Initial context is required when not resuming.")
|
|
757
767
|
raise typer.Exit(code=1)
|
|
@@ -24,9 +24,15 @@ from ouroboros.bigbang.pm_completion import (
|
|
|
24
24
|
from ouroboros.cli.formatters import console
|
|
25
25
|
from ouroboros.cli.formatters.panels import print_error, print_info, print_success, print_warning
|
|
26
26
|
from ouroboros.cli.formatters.prompting import multiline_prompt_async
|
|
27
|
-
from ouroboros.config import get_clarification_model
|
|
27
|
+
from ouroboros.config import get_clarification_model, get_llm_backend
|
|
28
28
|
from ouroboros.core.types import Result
|
|
29
29
|
from ouroboros.observability import LoggingConfig, configure_logging
|
|
30
|
+
from ouroboros.pm.handoff import build_pm_dev_handoff_command
|
|
31
|
+
from ouroboros.providers.factory import (
|
|
32
|
+
create_llm_adapter,
|
|
33
|
+
resolve_llm_backend,
|
|
34
|
+
resolve_llm_permission_mode,
|
|
35
|
+
)
|
|
30
36
|
|
|
31
37
|
app = typer.Typer(
|
|
32
38
|
name="pm",
|
|
@@ -58,6 +64,18 @@ def _create_pm_litellm_adapter() -> Any:
|
|
|
58
64
|
return LiteLLMAdapter()
|
|
59
65
|
|
|
60
66
|
|
|
67
|
+
def _raise_missing_litellm_dependency(exc: ModuleNotFoundError) -> None:
|
|
68
|
+
"""Convert a missing optional LiteLLM import into install guidance."""
|
|
69
|
+
if exc.name == "litellm" or "litellm" in str(exc):
|
|
70
|
+
msg = (
|
|
71
|
+
"PM interviews require the optional LiteLLM dependency. "
|
|
72
|
+
"Reinstall with `ouroboros-ai[litellm]`, or if you use uv tool: "
|
|
73
|
+
"`uv tool install --force --with litellm ouroboros-ai`."
|
|
74
|
+
)
|
|
75
|
+
raise RuntimeError(msg) from exc
|
|
76
|
+
raise exc
|
|
77
|
+
|
|
78
|
+
|
|
61
79
|
@app.callback(invoke_without_command=True)
|
|
62
80
|
def pm_command(
|
|
63
81
|
ctx: typer.Context,
|
|
@@ -111,9 +129,6 @@ def pm_command(
|
|
|
111
129
|
if ctx.invoked_subcommand is not None:
|
|
112
130
|
return
|
|
113
131
|
|
|
114
|
-
if model is None:
|
|
115
|
-
model = get_clarification_model()
|
|
116
|
-
|
|
117
132
|
if debug:
|
|
118
133
|
configure_logging(LoggingConfig(log_level="DEBUG"))
|
|
119
134
|
print_info("Debug mode enabled - showing verbose logs")
|
|
@@ -125,17 +140,36 @@ def pm_command(
|
|
|
125
140
|
else:
|
|
126
141
|
print_info("Starting new PM interview session...")
|
|
127
142
|
|
|
128
|
-
console.print(f" Model: [dim]{model}[/]\n")
|
|
129
|
-
|
|
130
143
|
try:
|
|
144
|
+
resolved_backend = resolve_llm_backend(get_llm_backend())
|
|
145
|
+
resolved_model = model or get_clarification_model(resolved_backend)
|
|
146
|
+
permission_mode = resolve_llm_permission_mode(
|
|
147
|
+
backend=resolved_backend,
|
|
148
|
+
use_case="interview",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
console.print(f" Model: [dim]{resolved_model}[/]\n")
|
|
152
|
+
if permission_mode == "bypassPermissions":
|
|
153
|
+
print_warning(
|
|
154
|
+
"Interview backend "
|
|
155
|
+
f"'{resolved_backend}' uses bypassPermissions for question generation."
|
|
156
|
+
)
|
|
157
|
+
|
|
131
158
|
asyncio.run(
|
|
132
159
|
_run_pm_interview(
|
|
133
160
|
resume_id=resume,
|
|
134
|
-
model=
|
|
161
|
+
model=resolved_model,
|
|
162
|
+
backend=resolved_backend,
|
|
135
163
|
debug=debug,
|
|
136
164
|
output_dir=output,
|
|
137
165
|
)
|
|
138
166
|
)
|
|
167
|
+
except ValueError as exc:
|
|
168
|
+
print_error(str(exc))
|
|
169
|
+
raise typer.Exit(code=1) from exc
|
|
170
|
+
except RuntimeError as exc:
|
|
171
|
+
print_error(str(exc))
|
|
172
|
+
raise typer.Exit(code=1) from exc
|
|
139
173
|
except KeyboardInterrupt:
|
|
140
174
|
print_info("\nPM interview interrupted. Progress has been saved.")
|
|
141
175
|
raise typer.Exit(code=0)
|
|
@@ -334,10 +368,54 @@ def _save_cli_pm_meta(session_id: str, engine: Any) -> None:
|
|
|
334
368
|
meta_path.write_text(json.dumps(meta, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
335
369
|
|
|
336
370
|
|
|
371
|
+
def _make_message_callback(debug: bool):
|
|
372
|
+
"""Create a debug callback for streaming local agent status."""
|
|
373
|
+
if not debug:
|
|
374
|
+
return None
|
|
375
|
+
|
|
376
|
+
def callback(msg_type: str, content: str) -> None:
|
|
377
|
+
if msg_type == "thinking":
|
|
378
|
+
first_line = content.split("\n")[0].strip()
|
|
379
|
+
display = first_line[:100] + "..." if len(first_line) > 100 else first_line
|
|
380
|
+
if display:
|
|
381
|
+
console.print(f" [dim]thinking:[/] {display}")
|
|
382
|
+
elif msg_type == "tool":
|
|
383
|
+
console.print(f" [yellow]tool:[/] {content}")
|
|
384
|
+
|
|
385
|
+
return callback
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
async def _continue_into_dev_interview(
|
|
389
|
+
seed_path: Path,
|
|
390
|
+
*,
|
|
391
|
+
debug: bool,
|
|
392
|
+
llm_backend: str | None,
|
|
393
|
+
) -> None:
|
|
394
|
+
"""Resolve a PM artifact path into interview context and start the dev interview."""
|
|
395
|
+
from ouroboros.cli.commands.init import _run_interview
|
|
396
|
+
from ouroboros.core.initial_context import resolve_initial_context_input
|
|
397
|
+
|
|
398
|
+
resolved_context = resolve_initial_context_input(str(seed_path), cwd=Path.cwd())
|
|
399
|
+
if resolved_context.is_err:
|
|
400
|
+
print_error(f"Failed to load PM seed for dev interview: {resolved_context.error.message}")
|
|
401
|
+
raise typer.Exit(code=1)
|
|
402
|
+
|
|
403
|
+
await _run_interview(
|
|
404
|
+
resolved_context.value,
|
|
405
|
+
resume_id=None,
|
|
406
|
+
state_dir=None,
|
|
407
|
+
use_orchestrator=False,
|
|
408
|
+
debug=debug,
|
|
409
|
+
workflow_runtime_backend=None,
|
|
410
|
+
llm_backend=llm_backend,
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
|
|
337
414
|
async def _run_pm_interview(
|
|
338
415
|
resume_id: str | None,
|
|
339
416
|
model: str,
|
|
340
|
-
|
|
417
|
+
backend: str | None,
|
|
418
|
+
debug: bool,
|
|
341
419
|
output_dir: str | None = None,
|
|
342
420
|
) -> None:
|
|
343
421
|
"""Run the PM interview loop.
|
|
@@ -348,16 +426,25 @@ async def _run_pm_interview(
|
|
|
348
426
|
Args:
|
|
349
427
|
resume_id: Optional session ID to resume.
|
|
350
428
|
model: LLM model identifier.
|
|
429
|
+
backend: Resolved LLM backend name.
|
|
351
430
|
debug: Enable debug output.
|
|
352
431
|
output_dir: Optional output directory for the generated PM document.
|
|
353
432
|
"""
|
|
354
433
|
from ouroboros.bigbang.pm_interview import PMInterviewEngine
|
|
355
434
|
|
|
356
435
|
try:
|
|
357
|
-
adapter =
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
436
|
+
adapter = create_llm_adapter(
|
|
437
|
+
backend=backend,
|
|
438
|
+
use_case="interview",
|
|
439
|
+
allowed_tools=None,
|
|
440
|
+
max_turns=5,
|
|
441
|
+
on_message=_make_message_callback(debug),
|
|
442
|
+
cwd=Path.cwd(),
|
|
443
|
+
)
|
|
444
|
+
except ModuleNotFoundError as exc:
|
|
445
|
+
if backend == "litellm":
|
|
446
|
+
_raise_missing_litellm_dependency(exc)
|
|
447
|
+
raise
|
|
361
448
|
engine = PMInterviewEngine.create(llm_adapter=adapter, model=model)
|
|
362
449
|
|
|
363
450
|
# Check for existing PM seeds before starting a new session
|
|
@@ -607,6 +694,22 @@ async def _run_pm_interview(
|
|
|
607
694
|
pm_dir = Path(output_dir) if output_dir else Path.cwd() / ".ouroboros"
|
|
608
695
|
pm_path = save_pm_document(seed, output_dir=pm_dir)
|
|
609
696
|
print_success(f"PM document saved: {pm_path}")
|
|
697
|
+
|
|
698
|
+
print_info(
|
|
699
|
+
"The PM seed is a handoff artifact for the dev interview, not the runnable Seed."
|
|
700
|
+
)
|
|
701
|
+
print_info(f"Next: {build_pm_dev_handoff_command(seed_path)}")
|
|
702
|
+
|
|
703
|
+
continue_to_dev = Confirm.ask(
|
|
704
|
+
"Continue into the dev interview now?",
|
|
705
|
+
default=True,
|
|
706
|
+
)
|
|
707
|
+
if continue_to_dev:
|
|
708
|
+
await _continue_into_dev_interview(
|
|
709
|
+
seed_path,
|
|
710
|
+
debug=debug,
|
|
711
|
+
llm_backend=backend,
|
|
712
|
+
)
|
|
610
713
|
else:
|
|
611
714
|
print_error(f"Failed to generate PM: {seed_result.error}")
|
|
612
715
|
elif state.rounds and not state.is_complete:
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""Helpers for resolving interview initial context from text or files."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
from ouroboros.bigbang.pm_seed import PMSeed
|
|
10
|
+
from ouroboros.core.errors import ValidationError
|
|
11
|
+
from ouroboros.core.security import InputValidator
|
|
12
|
+
from ouroboros.core.types import Result
|
|
13
|
+
|
|
14
|
+
_PM_SEED_SUFFIXES = {".json", ".yaml", ".yml"}
|
|
15
|
+
_TEXT_CONTEXT_SUFFIXES = {".md", ".markdown", ".txt", ".rst"}
|
|
16
|
+
_MAX_PATH_CANDIDATE_LENGTH = 240
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _is_pm_seed_candidate(seed_path: Path, raw_data: object) -> bool:
|
|
20
|
+
"""Return True when a file should be treated as a PM-seed artifact."""
|
|
21
|
+
if seed_path.stem.startswith("pm_seed_"):
|
|
22
|
+
return True
|
|
23
|
+
if isinstance(raw_data, dict):
|
|
24
|
+
pm_id = raw_data.get("pm_id")
|
|
25
|
+
if isinstance(pm_id, str) and pm_id.startswith("pm_seed_"):
|
|
26
|
+
return True
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _validate_pm_seed_mapping(
|
|
31
|
+
raw_data: dict[object, object], seed_path: Path
|
|
32
|
+
) -> Result[None, ValidationError]:
|
|
33
|
+
"""Validate the minimum PM-seed contract before conversion."""
|
|
34
|
+
pm_id = raw_data.get("pm_id")
|
|
35
|
+
product_name = raw_data.get("product_name")
|
|
36
|
+
goal = raw_data.get("goal")
|
|
37
|
+
|
|
38
|
+
has_pm_seed_filename = seed_path.stem.startswith("pm_seed_")
|
|
39
|
+
has_pm_seed_id = isinstance(pm_id, str) and pm_id.startswith("pm_seed_")
|
|
40
|
+
|
|
41
|
+
if (
|
|
42
|
+
not isinstance(pm_id, str)
|
|
43
|
+
or (not pm_id.strip())
|
|
44
|
+
or (not has_pm_seed_id and not has_pm_seed_filename)
|
|
45
|
+
):
|
|
46
|
+
return Result.err(
|
|
47
|
+
ValidationError(
|
|
48
|
+
"PM seed file must include a non-empty pm_id and either a 'pm_seed_' filename or pm_id",
|
|
49
|
+
field="initial_context",
|
|
50
|
+
value=str(seed_path),
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if not isinstance(product_name, str) or not product_name.strip():
|
|
55
|
+
return Result.err(
|
|
56
|
+
ValidationError(
|
|
57
|
+
"PM seed file must include a non-empty product_name",
|
|
58
|
+
field="initial_context",
|
|
59
|
+
value=str(seed_path),
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if not isinstance(goal, str) or not goal.strip():
|
|
64
|
+
return Result.err(
|
|
65
|
+
ValidationError(
|
|
66
|
+
"PM seed file must include a non-empty goal",
|
|
67
|
+
field="initial_context",
|
|
68
|
+
value=str(seed_path),
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return Result.ok(None)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _resolve_path_candidate(
|
|
76
|
+
context_candidate: str,
|
|
77
|
+
*,
|
|
78
|
+
cwd: str | Path | None = None,
|
|
79
|
+
) -> Path | None:
|
|
80
|
+
"""Return a plausible file-path candidate, or None for literal text."""
|
|
81
|
+
if "\n" in context_candidate or len(context_candidate) > _MAX_PATH_CANDIDATE_LENGTH:
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
candidate_path = Path(context_candidate).expanduser()
|
|
86
|
+
except (OSError, ValueError):
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
if not candidate_path.is_absolute() and cwd is not None:
|
|
90
|
+
candidate_path = Path(cwd).expanduser() / candidate_path
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
if candidate_path.exists() and candidate_path.is_file():
|
|
94
|
+
return candidate_path
|
|
95
|
+
except OSError:
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def load_pm_seed_as_context(seed_path: Path) -> Result[str, ValidationError]:
|
|
102
|
+
"""Load a PMSeed artifact and convert it into dev-interview context."""
|
|
103
|
+
try:
|
|
104
|
+
raw_data = yaml.safe_load(seed_path.read_text(encoding="utf-8"))
|
|
105
|
+
except (OSError, yaml.YAMLError) as exc:
|
|
106
|
+
return Result.err(
|
|
107
|
+
ValidationError(
|
|
108
|
+
f"Failed to load PM seed: {exc}",
|
|
109
|
+
field="initial_context",
|
|
110
|
+
value=str(seed_path),
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if not isinstance(raw_data, dict):
|
|
115
|
+
return Result.err(
|
|
116
|
+
ValidationError(
|
|
117
|
+
"PM seed file must contain an object mapping",
|
|
118
|
+
field="initial_context",
|
|
119
|
+
value=str(seed_path),
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
validation_result = _validate_pm_seed_mapping(raw_data, seed_path)
|
|
124
|
+
if validation_result.is_err:
|
|
125
|
+
return validation_result
|
|
126
|
+
|
|
127
|
+
pm_seed = PMSeed.from_dict(raw_data)
|
|
128
|
+
context = pm_seed.to_initial_context()
|
|
129
|
+
is_valid, error_message = InputValidator.validate_initial_context(context)
|
|
130
|
+
if not is_valid:
|
|
131
|
+
return Result.err(
|
|
132
|
+
ValidationError(
|
|
133
|
+
error_message,
|
|
134
|
+
field="initial_context",
|
|
135
|
+
value=str(seed_path),
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return Result.ok(context)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def resolve_initial_context_input(
|
|
143
|
+
initial_context: str,
|
|
144
|
+
*,
|
|
145
|
+
cwd: str | Path | None = None,
|
|
146
|
+
) -> Result[str, ValidationError]:
|
|
147
|
+
"""Resolve interview input from literal text or an existing file path."""
|
|
148
|
+
context_candidate = initial_context.strip()
|
|
149
|
+
if not context_candidate:
|
|
150
|
+
return Result.err(
|
|
151
|
+
ValidationError(
|
|
152
|
+
"Initial context cannot be empty",
|
|
153
|
+
field="initial_context",
|
|
154
|
+
value=initial_context,
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
candidate_path = _resolve_path_candidate(context_candidate, cwd=cwd)
|
|
159
|
+
if candidate_path is not None:
|
|
160
|
+
suffix = candidate_path.suffix.lower()
|
|
161
|
+
if suffix in _PM_SEED_SUFFIXES:
|
|
162
|
+
try:
|
|
163
|
+
raw_data = yaml.safe_load(candidate_path.read_text(encoding="utf-8"))
|
|
164
|
+
except (OSError, yaml.YAMLError) as exc:
|
|
165
|
+
return Result.err(
|
|
166
|
+
ValidationError(
|
|
167
|
+
f"Failed to read initial context file: {exc}",
|
|
168
|
+
field="initial_context",
|
|
169
|
+
value=str(candidate_path),
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if _is_pm_seed_candidate(candidate_path, raw_data):
|
|
174
|
+
return load_pm_seed_as_context(candidate_path)
|
|
175
|
+
|
|
176
|
+
if suffix in _TEXT_CONTEXT_SUFFIXES or suffix in _PM_SEED_SUFFIXES:
|
|
177
|
+
try:
|
|
178
|
+
file_context = candidate_path.read_text(encoding="utf-8")
|
|
179
|
+
except OSError as exc:
|
|
180
|
+
return Result.err(
|
|
181
|
+
ValidationError(
|
|
182
|
+
f"Failed to read initial context file: {exc}",
|
|
183
|
+
field="initial_context",
|
|
184
|
+
value=str(candidate_path),
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
is_valid, error_message = InputValidator.validate_initial_context(file_context)
|
|
189
|
+
if not is_valid:
|
|
190
|
+
return Result.err(
|
|
191
|
+
ValidationError(
|
|
192
|
+
error_message,
|
|
193
|
+
field="initial_context",
|
|
194
|
+
value=str(candidate_path),
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
return Result.ok(file_context)
|
|
198
|
+
|
|
199
|
+
is_valid, error_message = InputValidator.validate_initial_context(initial_context)
|
|
200
|
+
if not is_valid:
|
|
201
|
+
return Result.err(
|
|
202
|
+
ValidationError(
|
|
203
|
+
error_message,
|
|
204
|
+
field="initial_context",
|
|
205
|
+
value=initial_context,
|
|
206
|
+
)
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return Result.ok(initial_context)
|
{ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/src/ouroboros/mcp/tools/authoring_handlers.py
RENAMED
|
@@ -30,6 +30,7 @@ from ouroboros.bigbang.interview import (
|
|
|
30
30
|
from ouroboros.bigbang.seed_generator import SeedGenerator
|
|
31
31
|
from ouroboros.config import get_clarification_model
|
|
32
32
|
from ouroboros.core.errors import ValidationError
|
|
33
|
+
from ouroboros.core.initial_context import resolve_initial_context_input
|
|
33
34
|
from ouroboros.core.types import Result
|
|
34
35
|
from ouroboros.mcp.errors import MCPServerError, MCPToolError
|
|
35
36
|
from ouroboros.mcp.types import (
|
|
@@ -678,7 +679,16 @@ class InterviewHandler:
|
|
|
678
679
|
# Start new interview
|
|
679
680
|
if initial_context:
|
|
680
681
|
cwd = arguments.get("cwd") or os.getcwd()
|
|
681
|
-
|
|
682
|
+
resolved_context = resolve_initial_context_input(initial_context, cwd=cwd)
|
|
683
|
+
if resolved_context.is_err:
|
|
684
|
+
return Result.err(
|
|
685
|
+
MCPToolError(
|
|
686
|
+
str(resolved_context.error),
|
|
687
|
+
tool_name="ouroboros_interview",
|
|
688
|
+
)
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
result = await engine.start_interview(resolved_context.value, cwd=cwd)
|
|
682
692
|
if result.is_err:
|
|
683
693
|
return Result.err(
|
|
684
694
|
MCPToolError(
|
|
@@ -762,7 +772,7 @@ class InterviewHandler:
|
|
|
762
772
|
await self._emit_event(
|
|
763
773
|
interview_started(
|
|
764
774
|
state.interview_id,
|
|
765
|
-
|
|
775
|
+
resolved_context.value,
|
|
766
776
|
)
|
|
767
777
|
)
|
|
768
778
|
|
|
@@ -48,6 +48,7 @@ from ouroboros.mcp.types import (
|
|
|
48
48
|
ToolInputType,
|
|
49
49
|
)
|
|
50
50
|
from ouroboros.persistence.brownfield import BrownfieldRepo, BrownfieldStore
|
|
51
|
+
from ouroboros.pm.handoff import build_pm_dev_handoff_next_step
|
|
51
52
|
from ouroboros.providers import create_llm_adapter
|
|
52
53
|
|
|
53
54
|
log = structlog.get_logger()
|
|
@@ -1230,6 +1231,7 @@ class PMInterviewHandler:
|
|
|
1230
1231
|
|
|
1231
1232
|
seed = seed_result.value
|
|
1232
1233
|
|
|
1234
|
+
# Save seed to ~/.ouroboros/seeds/ (idempotent — overwrites on retry)
|
|
1233
1235
|
# Save seed and PM document with recovery contract
|
|
1234
1236
|
try:
|
|
1235
1237
|
seed_path = engine.save_pm_seed(seed)
|
|
@@ -1258,6 +1260,8 @@ class PMInterviewHandler:
|
|
|
1258
1260
|
)
|
|
1259
1261
|
)
|
|
1260
1262
|
|
|
1263
|
+
next_step = build_pm_dev_handoff_next_step(seed_path)
|
|
1264
|
+
|
|
1261
1265
|
return Result.ok(
|
|
1262
1266
|
MCPToolResult(
|
|
1263
1267
|
content=(
|
|
@@ -1265,10 +1269,13 @@ class PMInterviewHandler:
|
|
|
1265
1269
|
type=ContentType.TEXT,
|
|
1266
1270
|
text=(
|
|
1267
1271
|
f"PM seed generated: {seed.product_name}\n"
|
|
1268
|
-
f"
|
|
1272
|
+
f"PM seed: {seed_path}\n"
|
|
1269
1273
|
f"PM document: {pm_path}\n\n"
|
|
1274
|
+
"This PM seed is a handoff artifact for the dev interview, "
|
|
1275
|
+
"not the runnable Seed.\n"
|
|
1270
1276
|
f"Deferred items: {len(seed.deferred_items)}\n"
|
|
1271
|
-
f"Decide-later items: {len(seed.decide_later_items)}"
|
|
1277
|
+
f"Decide-later items: {len(seed.decide_later_items)}\n"
|
|
1278
|
+
f"Next: {next_step}"
|
|
1272
1279
|
),
|
|
1273
1280
|
),
|
|
1274
1281
|
),
|
|
@@ -1276,8 +1283,11 @@ class PMInterviewHandler:
|
|
|
1276
1283
|
meta={
|
|
1277
1284
|
"session_id": session_id,
|
|
1278
1285
|
"seed_path": str(seed_path),
|
|
1286
|
+
"pm_seed_path": str(seed_path),
|
|
1279
1287
|
"pm_path": str(pm_path),
|
|
1280
|
-
"
|
|
1288
|
+
"artifact_kind": "pm_seed",
|
|
1289
|
+
"runnable": False,
|
|
1290
|
+
"next_step": next_step,
|
|
1281
1291
|
},
|
|
1282
1292
|
)
|
|
1283
1293
|
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Shared PM handoff messaging helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def build_pm_dev_handoff_command(seed_path: Path | str) -> str:
|
|
9
|
+
"""Return the canonical command for continuing from a PM seed."""
|
|
10
|
+
return f"ouroboros init start {seed_path}"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def build_pm_dev_handoff_next_step(seed_path: Path | str) -> str:
|
|
14
|
+
"""Return the canonical PM-to-dev handoff message."""
|
|
15
|
+
return (
|
|
16
|
+
f"Run '{build_pm_dev_handoff_command(seed_path)}' to continue into the dev interview. "
|
|
17
|
+
"The runnable Seed is generated after that dev interview completes."
|
|
18
|
+
)
|
{ouroboros_ai-0.26.5.dev5 → ouroboros_ai-0.26.5.dev7}/tests/unit/cli/test_init_pm_seed_detection.py
RENAMED
|
@@ -16,6 +16,7 @@ from ouroboros.cli.commands.init import (
|
|
|
16
16
|
_load_pm_seed_as_context,
|
|
17
17
|
_notify_pm_seed_detected,
|
|
18
18
|
_prompt_pm_seed_selection,
|
|
19
|
+
start,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
# ---------------------------------------------------------------------------
|
|
@@ -550,3 +551,36 @@ class TestPrdSeedConfirmationFlow:
|
|
|
550
551
|
assert parsed["goal"] == "End-to-end testing"
|
|
551
552
|
assert "Analytics" in parsed["deferred_items"]
|
|
552
553
|
assert "Hosting provider" in parsed["decide_later_items"]
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
class TestStartCommandPathResolution:
|
|
557
|
+
"""Tests for starting the dev interview from a PM artifact path."""
|
|
558
|
+
|
|
559
|
+
def test_start_resolves_pm_seed_path_before_running_interview(self, tmp_path: Path) -> None:
|
|
560
|
+
seed_path = tmp_path / "pm_seed_taskflow.json"
|
|
561
|
+
seed_path.write_text(
|
|
562
|
+
"""{
|
|
563
|
+
"pm_id": "pm_seed_taskflow",
|
|
564
|
+
"product_name": "TaskFlow",
|
|
565
|
+
"goal": "Help teams manage tasks",
|
|
566
|
+
"constraints": ["Offline support"],
|
|
567
|
+
"success_criteria": ["Tasks sync correctly"],
|
|
568
|
+
"user_stories": [],
|
|
569
|
+
"deferred_items": [],
|
|
570
|
+
"decide_later_items": []
|
|
571
|
+
}
|
|
572
|
+
""",
|
|
573
|
+
encoding="utf-8",
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
with (
|
|
577
|
+
patch.object(Path, "home", return_value=tmp_path),
|
|
578
|
+
patch("ouroboros.cli.commands.init.asyncio.run"),
|
|
579
|
+
patch("ouroboros.cli.commands.init._run_interview") as mock_run_interview,
|
|
580
|
+
patch("ouroboros.cli.commands.init.print_info"),
|
|
581
|
+
):
|
|
582
|
+
start(context=str(seed_path), resume=None)
|
|
583
|
+
|
|
584
|
+
resolved_context = mock_run_interview.call_args.args[0]
|
|
585
|
+
assert "TaskFlow" in resolved_context
|
|
586
|
+
assert str(seed_path) not in resolved_context
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from unittest.mock import patch
|
|
4
4
|
|
|
5
|
+
import pytest
|
|
5
6
|
from typer.testing import CliRunner
|
|
6
7
|
|
|
7
8
|
from ouroboros.cli.main import app
|
|
@@ -9,16 +10,35 @@ from ouroboros.cli.main import app
|
|
|
9
10
|
runner = CliRunner()
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
@
|
|
13
|
-
|
|
13
|
+
@pytest.mark.parametrize(
|
|
14
|
+
("configured_backend", "resolved_backend"),
|
|
15
|
+
[
|
|
16
|
+
("codex", "codex"),
|
|
17
|
+
("claude_code", "claude_code"),
|
|
18
|
+
("litellm", "litellm"),
|
|
19
|
+
],
|
|
20
|
+
)
|
|
14
21
|
def test_pm_uses_configured_clarification_model_when_option_omitted(
|
|
15
|
-
|
|
22
|
+
configured_backend: str,
|
|
23
|
+
resolved_backend: str,
|
|
16
24
|
) -> None:
|
|
17
25
|
"""The bare `pm` command should resolve its model from config."""
|
|
18
|
-
|
|
26
|
+
with (
|
|
27
|
+
patch("ouroboros.cli.commands.pm.get_llm_backend", return_value=configured_backend),
|
|
28
|
+
patch(
|
|
29
|
+
"ouroboros.cli.commands.pm.resolve_llm_backend",
|
|
30
|
+
return_value=resolved_backend,
|
|
31
|
+
),
|
|
32
|
+
patch(
|
|
33
|
+
"ouroboros.cli.commands.pm.get_clarification_model",
|
|
34
|
+
return_value="default",
|
|
35
|
+
) as mock_get_clarification_model,
|
|
36
|
+
patch("ouroboros.cli.commands.pm._run_pm_interview") as mock_run_pm_interview,
|
|
37
|
+
):
|
|
38
|
+
result = runner.invoke(app, ["pm"], input="n\n")
|
|
19
39
|
|
|
20
40
|
assert result.exit_code == 0
|
|
21
|
-
mock_get_clarification_model.assert_called_once_with()
|
|
41
|
+
mock_get_clarification_model.assert_called_once_with(resolved_backend)
|
|
22
42
|
mock_run_pm_interview.assert_called_once()
|
|
23
43
|
assert mock_run_pm_interview.call_args.kwargs["model"] == "default"
|
|
24
44
|
assert "Model:" in result.output
|