devex-cli 0.29.2__tar.gz → 0.30.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- devex_cli-0.30.1/.devague/frames/devex-now-reads-qodo-pr-review-findings-structural.json +303 -0
- devex_cli-0.30.1/.devague/plans/devex-now-reads-qodo-pr-review-findings-structural.json +271 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.github/workflows/test.yml +12 -2
- {devex_cli-0.29.2 → devex_cli-0.30.1}/CHANGELOG.md +27 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/CLAUDE.md +12 -1
- {devex_cli-0.29.2 → devex_cli-0.30.1}/PKG-INFO +3 -1
- devex_cli-0.30.1/docs/plans/2026-06-19-devex-now-reads-qodo-pr-review-findings-structural.md +68 -0
- devex_cli-0.30.1/docs/specs/2026-06-19-devex-now-reads-qodo-pr-review-findings-structural.md +58 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/pyproject.toml +12 -1
- {devex_cli-0.29.2 → devex_cli-0.30.1}/sonar-project.properties +10 -1
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/cli.py +117 -1
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/pr_briefing.md.j2 +1 -1
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_qodo.py +75 -3
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/await_.py +1 -1
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/read.py +2 -2
- devex_cli-0.30.1/src/devex/commands/reviewer/SKILL.md +55 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/backends/acp.yaml +10 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/backends/claude-code.yaml +10 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/backends/codex.yaml +10 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/backends/copilot.yaml +10 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/config.md.j2 +11 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/failed.md.j2 +11 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/review_list.md.j2 +13 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/review_resolve.md.j2 +11 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/rules.md.j2 +13 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/assets/unsupported.md.j2 +24 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/scripts/_footer.py +22 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/scripts/next_step.py +36 -0
- devex_cli-0.30.1/src/devex/commands/reviewer/scripts/reviewer.py +307 -0
- devex_cli-0.30.1/src/devex/core/qodo.py +114 -0
- devex_cli-0.30.1/tests/commands/pr/__init__.py +0 -0
- devex_cli-0.30.1/tests/commands/pr/fixtures/gh/.gitkeep +0 -0
- devex_cli-0.30.1/tests/commands/pr/test_briefing_findings.py +98 -0
- devex_cli-0.30.1/tests/commands/pr/test_qodo.py +189 -0
- devex_cli-0.30.1/tests/commands/push/__init__.py +0 -0
- devex_cli-0.30.1/tests/commands/test_reviewer.py +256 -0
- devex_cli-0.30.1/tests/core/__init__.py +0 -0
- devex_cli-0.30.1/tests/core/test_qodo_adapter.py +158 -0
- devex_cli-0.30.1/tests/fixtures/claude-code/empty/.gitkeep +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/test_footer_hints.py +1 -0
- devex_cli-0.30.1/tests/test_packaging_qodo_extra.py +45 -0
- devex_cli-0.30.1/tests/test_reviewer_invariant_docs.py +31 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/uv.lock +20 -3
- devex_cli-0.29.2/tests/commands/pr/test_qodo.py +0 -82
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/agent-config/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/agent-config/scripts/show.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/ask-colleague/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/ask-colleague/prompts/review.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/ask-colleague/prompts/write.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/cicd/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/communicate/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/run-tests/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/sonarclaude/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/think/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/think/scripts/think.sh +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/version-bump/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.claude/skills/version-bump/scripts/bump.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.devague/frames/devex-now-turns-a-push-into-continuous-pr-manageme.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.devague/frames/every-devex-command-now-closes-with-a-deterministi.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.devague/plans/devex-now-turns-a-push-into-continuous-pr-manageme.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.devague/plans/every-devex-command-now-closes-with-a-deterministi.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.flake8 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.github/workflows/publish.yml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.gitignore +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.markdownlint-cli2.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.pre-commit-config.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/.python-version +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/LICENSE +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/README.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/culture.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/plans/2026-05-29-devex-now-turns-a-push-into-continuous-pr-manageme.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/plans/2026-05-29-every-devex-command-now-closes-with-a-deterministi.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/skill-sources.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/specs/2026-05-29-devex-now-turns-a-push-into-continuous-pr-manageme.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/specs/2026-05-29-every-devex-command-now-closes-with-a-deterministi.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/superpowers/plans/2026-04-18-agex-v0.1.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/superpowers/plans/2026-05-10-agex-pr.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/superpowers/specs/2026-04-18-agex-design.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/superpowers/specs/2026-04-26-agex-doctor.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/docs/superpowers/specs/2026-05-10-agex-pr-design.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/__main__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/acp/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/acp/probe.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/capabilities/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/capabilities/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/capabilities/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/capabilities/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/claude_code/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/claude_code/probe.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/codex/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/codex/probe.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/copilot/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/backends/copilot/probe.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/assets/report.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/references/design.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/scripts/_footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/scripts/doctor.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/doctor/scripts/next_step.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/assets/topics/devex.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/references/.gitkeep +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/scripts/_footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/scripts/explain.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/explain/scripts/next_step.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/assets/hooks/claude-code.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/references/.gitkeep +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/scripts/install.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/gamify/scripts/next_step.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/assets/table.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/references/.gitkeep +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/scripts/_footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/scripts/next_step.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/scripts/read.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/hook/scripts/write.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/menu.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/cicd/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/gamify/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/gamify/assets/skill-template/claude-code/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/introspect/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/introspect/assets/skill-template/claude-code/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/levelup/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/levelup/assets/skill-template/claude-code/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/visualize/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/assets/topics/visualize/assets/skill-template/claude-code/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/references/.gitkeep +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/scripts/learn.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/learn/scripts/next_step.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/assets/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/assets/sections.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/references/.gitkeep +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/scripts/_footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/scripts/next_step.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/overview/scripts/overview.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/rules/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/rules/lint_rules.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/rules/next_step_rules.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/delta.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/lint_result.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/pr_await_detached.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/pr_open_result.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/pr_reply_result.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/assets/templates/pr_review_result.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_await_worker.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_deploy.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_detach.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_journal.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_readiness.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_sonar.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/_webhook.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/delta.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/lint.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/open_.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/reply.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/pr/scripts/review.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/assets/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/assets/backends/acp.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/assets/backends/claude-code.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/assets/backends/codex.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/assets/backends/copilot.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/scripts/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/commands/push/scripts/push.py +0 -0
- {devex_cli-0.29.2/src/devex/core → devex_cli-0.30.1/src/devex/commands/reviewer}/__init__.py +0 -0
- {devex_cli-0.29.2/src/devex/core → devex_cli-0.30.1/src/devex/commands/reviewer}/assets/__init__.py +0 -0
- {devex_cli-0.29.2/tests → devex_cli-0.30.1/src/devex/commands/reviewer/assets/backends}/__init__.py +0 -0
- {devex_cli-0.29.2/tests/commands/pr/fixtures/gh → devex_cli-0.30.1/src/devex/commands/reviewer/references}/.gitkeep +0 -0
- {devex_cli-0.29.2/tests/backends → devex_cli-0.30.1/src/devex/commands/reviewer/scripts}/__init__.py +0 -0
- {devex_cli-0.29.2/tests/commands → devex_cli-0.30.1/src/devex/core}/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/_jsonl.py +0 -0
- {devex_cli-0.29.2/tests/commands/pr → devex_cli-0.30.1/src/devex/core/assets}/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/assets/backends/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/assets/backends/neutral.yaml +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/assets/footer.md.j2 +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/backend.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/capabilities.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/config.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/github.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/hook_io.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/journal.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/paths.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/prog.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/render.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/skill_loader.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/src/devex/core/webhook.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tester-agents/claude/.claude/settings.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tester-agents/claude/.claude/skills +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tester-agents/claude/CLAUDE.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tester-agents/claude/README.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tester-agents/claude/culture.yaml +0 -0
- {devex_cli-0.29.2/tests/commands/push → devex_cli-0.30.1/tests}/__init__.py +0 -0
- {devex_cli-0.29.2/tests/core → devex_cli-0.30.1/tests/backends}/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/backends/test_claude_code_probe.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/backends/test_stub_probes.py +0 -0
- /devex_cli-0.29.2/tests/fixtures/claude-code/empty/.gitkeep → /devex_cli-0.30.1/tests/commands/__init__.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/fixtures/gh/pr_checks_42.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/fixtures/gh/pr_comments_42.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/fixtures/gh/qodo_summary_comment.html +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/fixtures/journals/dogfood_40.jsonl +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_await.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_await_detach.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_delta.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_deploy.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_lint.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_lint_rules.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_open.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_read.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_readiness.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_reply.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_review.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/pr/test_webhook_helper.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/push/test_push.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/push/test_push_backends.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/test_doctor.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/test_explain.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/test_gamify.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/test_hook.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/test_learn.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/test_overview.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/commands/test_prog_propagation.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/conftest.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_backend.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_capabilities.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_config.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_footer.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_github.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_hook_io.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_journal.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_paths.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_prog.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_render.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_resolve_backend.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_skill_loader.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_version_lookup.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_webhook.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/core/test_webhook_live.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/malformed/.claude/hooks.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/malformed/.claude/settings.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/malformed/.claude/skills/bad/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/malformed/.claude/skills/broken-yaml/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/typical/.claude/hooks.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/typical/.claude/settings.json +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/typical/.claude/skills/example/SKILL.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/fixtures/claude-code/typical/CLAUDE.md +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/test_cli_dispatch.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/test_cli_errors.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/test_cli_smoke.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/test_footer_guarantee.py +0 -0
- {devex_cli-0.29.2 → devex_cli-0.30.1}/tests/test_skill_md_consistency.py +0 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "devex-now-reads-qodo-pr-review-findings-structural",
|
|
3
|
+
"title": "devex now reads Qodo PR-review findings structurally through the installed qodo-cli instead of regex-scraping the bot's HTML comment \u2014 richer, more robust findings with a graceful fallback when qodo-cli is absent",
|
|
4
|
+
"schema_version": 1,
|
|
5
|
+
"status": "exported",
|
|
6
|
+
"created": "2026-06-19T07:04:36Z",
|
|
7
|
+
"updated": "2026-06-19T08:27:23Z",
|
|
8
|
+
"claims": [
|
|
9
|
+
{
|
|
10
|
+
"id": "c1",
|
|
11
|
+
"kind": "announcement",
|
|
12
|
+
"text": "devex now reads Qodo PR-review findings structurally through the installed qodo-cli instead of regex-scraping the bot's HTML comment \u2014 richer, more robust findings with a graceful fallback when qodo-cli is absent",
|
|
13
|
+
"origin": "user",
|
|
14
|
+
"status": "confirmed",
|
|
15
|
+
"honesty_conditions": [
|
|
16
|
+
{
|
|
17
|
+
"id": "h3",
|
|
18
|
+
"text": "Installing 'devex-cli[qodo]' and running 'devex pr read' on a Qodo-reviewed PR produces a strictly richer briefing than today, while an install WITHOUT the extra is byte-for-byte unchanged \u2014 proving the integration is purely additive.",
|
|
19
|
+
"status": "confirmed"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"hard_questions": [],
|
|
23
|
+
"links": []
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "c2",
|
|
27
|
+
"kind": "audience",
|
|
28
|
+
"text": "The autonomous agent running 'devex pr read' / 'devex pr await' on an AgentCulture repo (and the human, e.g. Ori, reviewing the resulting briefing) \u2014 both currently get Qodo findings filtered through a fragile HTML scraper.",
|
|
29
|
+
"origin": "llm",
|
|
30
|
+
"status": "confirmed",
|
|
31
|
+
"honesty_conditions": [
|
|
32
|
+
{
|
|
33
|
+
"id": "h6",
|
|
34
|
+
"text": "grep confirms _qodo.parse is today the SOLE source of Qodo findings feeding both 'pr read' and 'pr await' (read.py + await_.py call it), so both consumers inherit any improvement to that seam.",
|
|
35
|
+
"status": "confirmed"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"hard_questions": [],
|
|
39
|
+
"links": []
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "c3",
|
|
43
|
+
"kind": "before_state",
|
|
44
|
+
"text": "devex extracts Qodo findings by stdlib-regex-scraping the bot's 'Code Review by Qodo' HTML comment in _qodo.py \u2014 defensive, lossy (no severity/type/categories/agent_prompt), and the historical source of a ReDoS SonarCloud hotspot.",
|
|
45
|
+
"origin": "llm",
|
|
46
|
+
"status": "confirmed",
|
|
47
|
+
"honesty_conditions": [
|
|
48
|
+
{
|
|
49
|
+
"id": "h7",
|
|
50
|
+
"text": "git history confirms _qodo.py parses the bot's HTML with stdlib regex and that a python:S5852 ReDoS hotspot was previously raised on a Qodo-parsing regex (commit history / SonarCloud).",
|
|
51
|
+
"status": "confirmed"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"hard_questions": [],
|
|
55
|
+
"links": []
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "c4",
|
|
59
|
+
"kind": "after_state",
|
|
60
|
+
"text": "When qodo-cli is on PATH, devex sources Qodo findings from 'qodo review list --json' (the tool that owns Qodo's format) \u2014 gaining per-finding severity/type/categories and self-maintaining as the format evolves \u2014 and falls back to the existing HTML scraper unchanged when qodo-cli is absent or errors.",
|
|
61
|
+
"origin": "llm",
|
|
62
|
+
"status": "confirmed",
|
|
63
|
+
"honesty_conditions": [
|
|
64
|
+
{
|
|
65
|
+
"id": "h8",
|
|
66
|
+
"text": "On a Qodo-reviewed PR with [qodo] installed, 'pr read' renders per-finding severity/type/categories that are absent from today's output; with the extra removed the rendered output is unchanged.",
|
|
67
|
+
"status": "confirmed"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"hard_questions": [],
|
|
71
|
+
"links": []
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "c5",
|
|
75
|
+
"kind": "why_it_matters",
|
|
76
|
+
"text": "It moves the parsing burden onto the tool that owns the format, shrinks devex's brittle regex surface (less ReDoS/maintenance risk), and enriches the briefing \u2014 all without adding a runtime dependency or changing the default install.",
|
|
77
|
+
"origin": "llm",
|
|
78
|
+
"status": "confirmed",
|
|
79
|
+
"honesty_conditions": [
|
|
80
|
+
{
|
|
81
|
+
"id": "h9",
|
|
82
|
+
"text": "After the change pyproject's runtime 'dependencies' is still [] and a test proves the qodo-cli source is preferred over the regex scraper whenever the adapter reports the capability available.",
|
|
83
|
+
"status": "confirmed"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"hard_questions": [],
|
|
87
|
+
"links": []
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "c6",
|
|
91
|
+
"kind": "boundary",
|
|
92
|
+
"text": "v1 is READ-ONLY and confined to Qodo-finding extraction for 'pr read' / 'pr await'. It does NOT delegate comment resolution to 'qodo review resolve' (would expand the mutation surface), does NOT add 'qodo rules get' (new non-gh network egress), and does NOT remove the HTML scraper (it stays as the fallback).",
|
|
93
|
+
"origin": "llm",
|
|
94
|
+
"status": "rejected",
|
|
95
|
+
"honesty_conditions": [],
|
|
96
|
+
"hard_questions": [],
|
|
97
|
+
"links": []
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "c7",
|
|
101
|
+
"kind": "success_signal",
|
|
102
|
+
"text": "With qodo-cli installed, 'devex pr read' on a PR with Qodo findings shows the same counts/total/url as before PLUS per-finding severity/type; with qodo-cli uninstalled, output is byte-identical to today; no new failing path (any qodo-cli error degrades silently to the scraper).",
|
|
103
|
+
"origin": "llm",
|
|
104
|
+
"status": "confirmed",
|
|
105
|
+
"honesty_conditions": [
|
|
106
|
+
{
|
|
107
|
+
"id": "h10",
|
|
108
|
+
"text": "Snapshot tests prove: qodo present -> briefing strictly a superset of today's; qodo absent -> output byte-identical; and no degradation path produces a non-zero exit.",
|
|
109
|
+
"status": "confirmed"
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"hard_questions": [],
|
|
113
|
+
"links": []
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"id": "c8",
|
|
117
|
+
"kind": "decision",
|
|
118
|
+
"text": "devex invokes qodo as a SUBPROCESS of its console script ('qodo review list --json'), not a Python import \u2014 matching devex's existing thin 'gh' shellout pattern (core/github.py) and binding only to qodo-cli's stable --json contract, never its private modules.",
|
|
119
|
+
"origin": "llm",
|
|
120
|
+
"status": "rejected",
|
|
121
|
+
"honesty_conditions": [],
|
|
122
|
+
"hard_questions": [],
|
|
123
|
+
"links": []
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"id": "c9",
|
|
127
|
+
"kind": "decision",
|
|
128
|
+
"text": "The optional extra is 'devex-cli[qodo] = [\"qodo-cli\"]' \u2014 it only ensures the 'qodo' console script lands on PATH; runtime dependencies = [] is unchanged, mirroring the reterminal-cli '[graphics]' optional-capability pattern.",
|
|
129
|
+
"origin": "llm",
|
|
130
|
+
"status": "confirmed",
|
|
131
|
+
"honesty_conditions": [],
|
|
132
|
+
"hard_questions": [],
|
|
133
|
+
"links": []
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "c10",
|
|
137
|
+
"kind": "decision",
|
|
138
|
+
"text": "Availability is detected lazily at call time (shutil.which('qodo') + a bounded subprocess run); exit code != 0 (e.g. 2 = no ~/.qodo config / gh absent), a timeout, or unparseable JSON all degrade to the existing HTML scraper. Detection/parsing never raises out of _qodo.",
|
|
139
|
+
"origin": "llm",
|
|
140
|
+
"status": "rejected",
|
|
141
|
+
"honesty_conditions": [],
|
|
142
|
+
"hard_questions": [
|
|
143
|
+
{
|
|
144
|
+
"id": "q1",
|
|
145
|
+
"text": "risk: qodo-cli's exit-2 'env/setup error' (missing ~/.qodo/config.json, gh absent, API error) must be treated as 'degrade to scraper', NOT surfaced as a devex error \u2014 otherwise installing the extra could make pr read noisier than not installing it.",
|
|
146
|
+
"resolved": false,
|
|
147
|
+
"blocking": false
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
"links": []
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"id": "c11",
|
|
154
|
+
"kind": "requirement",
|
|
155
|
+
"text": "_qodo.parse must return the SAME {counts, total, findings, url} shape regardless of source, enriched with optional per-finding 'severity'/'type'/'categories' keys that are simply None/absent on the scraper path \u2014 so pr read / pr await templates need no branching on source.",
|
|
156
|
+
"origin": "llm",
|
|
157
|
+
"status": "confirmed",
|
|
158
|
+
"honesty_conditions": [
|
|
159
|
+
{
|
|
160
|
+
"id": "h1",
|
|
161
|
+
"text": "The merged shape round-trips: a snapshot/unit test feeds a representative 'qodo review list --json' payload AND a representative HTML comment through _qodo.parse and asserts both yield the same {counts,total,findings,url} keys, with severity/type/categories present from JSON and None/absent from HTML.",
|
|
162
|
+
"status": "confirmed"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"hard_questions": [],
|
|
166
|
+
"links": []
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"id": "c12",
|
|
170
|
+
"kind": "requirement",
|
|
171
|
+
"text": "When qodo-cli is not installed, every existing test and every byte of 'devex pr read' / 'pr await' output is unchanged \u2014 the structured path is strictly additive and gated on qodo-cli being present AND succeeding.",
|
|
172
|
+
"origin": "llm",
|
|
173
|
+
"status": "confirmed",
|
|
174
|
+
"honesty_conditions": [
|
|
175
|
+
{
|
|
176
|
+
"id": "h2",
|
|
177
|
+
"text": "A guard test simulates 'qodo' absent (which() returns None / subprocess unavailable) and asserts _qodo.parse falls back to the scraper and pr read output byte-matches the existing snapshot.",
|
|
178
|
+
"status": "confirmed"
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
"hard_questions": [],
|
|
182
|
+
"links": []
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "c13",
|
|
186
|
+
"kind": "non_goal",
|
|
187
|
+
"text": "Delegating PR-comment resolution to 'qodo review resolve' and surfacing org rules via 'qodo rules get' are explicitly out of scope for v1 \u2014 they touch the mutation surface and a new network-egress class respectively, and belong in a follow-up.",
|
|
188
|
+
"origin": "llm",
|
|
189
|
+
"status": "rejected",
|
|
190
|
+
"honesty_conditions": [],
|
|
191
|
+
"hard_questions": [],
|
|
192
|
+
"links": []
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"id": "c14",
|
|
196
|
+
"kind": "boundary",
|
|
197
|
+
"text": "v1 ships a new 'reviewer' noun \u2014 devex's deterministic-markdown home for managing the Qodo reviewer (rules semantic-search, review-comment triage/resolve, repo reviewer config) \u2014 AND enriches existing 'pr read'/'pr await' findings, all through ONE qodo-cli adapter seam. devex wraps qodo-cli's output in its own markdown briefing + per-backend 'Next step:' footer; it never forks, vendors, or reimplements Qodo logic. When the [qodo] extra is absent every reviewer verb degrades to an exit-0 'unsupported' markdown notice (invariant #5).",
|
|
198
|
+
"origin": "llm",
|
|
199
|
+
"status": "confirmed",
|
|
200
|
+
"honesty_conditions": [
|
|
201
|
+
{
|
|
202
|
+
"id": "h11",
|
|
203
|
+
"text": "devex ships NO vendored copy of qodo logic (no qodo module under src/devex); a test asserts every 'reviewer' verb exits 0 with the unsupported markdown notice when 'qodo' is unimportable.",
|
|
204
|
+
"status": "confirmed"
|
|
205
|
+
}
|
|
206
|
+
],
|
|
207
|
+
"hard_questions": [],
|
|
208
|
+
"links": []
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"id": "c15",
|
|
212
|
+
"kind": "decision",
|
|
213
|
+
"text": "Integration is IN-PROCESS: the [qodo] extra ('devex-cli[qodo] = [\"qodo-cli\"]') installs the 'qodo' package into devex's env; a single thin adapter gates on 'import qodo' and invokes 'qodo.cli.main([...,\"--json\"])' capturing stdout + catching SystemExit \u2014 binding ONLY to qodo-cli's stable --json/CLI contract, never its private 'qodo.cli._*' modules. The adapter is the one and only seam to qodo-cli.",
|
|
214
|
+
"origin": "llm",
|
|
215
|
+
"status": "confirmed",
|
|
216
|
+
"honesty_conditions": [],
|
|
217
|
+
"hard_questions": [],
|
|
218
|
+
"links": []
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"id": "c16",
|
|
222
|
+
"kind": "decision",
|
|
223
|
+
"text": "Two follow-ups are filed at design time: (a) an issue on agentculture/qodo-cli requesting a documented public Python API (e.g. 'qodo.api' returning structured data) for integration; (b) an issue on agentculture/devex to migrate the adapter from main()-capture onto that public API once it lands. The single adapter seam keeps that migration a one-file change.",
|
|
224
|
+
"origin": "llm",
|
|
225
|
+
"status": "confirmed",
|
|
226
|
+
"honesty_conditions": [],
|
|
227
|
+
"hard_questions": [],
|
|
228
|
+
"links": []
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"id": "c17",
|
|
232
|
+
"kind": "after_state",
|
|
233
|
+
"text": "An agent can run 'devex reviewer rules \"<q>\"', 'devex reviewer review list|resolve', and 'devex reviewer config show|validate|init' to manage Qodo entirely through devex's uniform markdown+footer surface, and 'pr read'/'pr await' gain per-finding severity/type/categories \u2014 all powered by the in-process qodo-cli adapter, with a clean unsupported-notice when the extra isn't installed.",
|
|
234
|
+
"origin": "llm",
|
|
235
|
+
"status": "confirmed",
|
|
236
|
+
"honesty_conditions": [
|
|
237
|
+
{
|
|
238
|
+
"id": "h12",
|
|
239
|
+
"text": "A test enumerates each 'reviewer' verb (rules / review list / review resolve / config show|validate|init) and asserts it maps to the expected 'qodo.cli.main([...])' argv through the adapter.",
|
|
240
|
+
"status": "confirmed"
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
"hard_questions": [],
|
|
244
|
+
"links": []
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"id": "c18",
|
|
248
|
+
"kind": "requirement",
|
|
249
|
+
"text": "Invariant docs must be updated: 'reviewer review resolve' MUTATES GitHub (reply+ack+resolve), so invariant #4's side-effect set is extended to name it; and the rules/review network I/O performed inside qodo-cli (Qodo rules API + gh) is documented as an extension of the 'pr' namespace network carve-out. No new egress originates in devex itself \u2014 it all flows through the imported qodo-cli.",
|
|
250
|
+
"origin": "llm",
|
|
251
|
+
"status": "confirmed",
|
|
252
|
+
"honesty_conditions": [
|
|
253
|
+
{
|
|
254
|
+
"id": "h4",
|
|
255
|
+
"text": "The PR updates CLAUDE.md invariant #4 to name 'reviewer review resolve' in the side-effect set and documents the qodo-cli-mediated network egress as a pr-namespace carve-out extension; a doc/guard test or explicit review confirms devex itself opens no new socket (all network is inside the imported qodo-cli).",
|
|
256
|
+
"status": "confirmed"
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
"hard_questions": [],
|
|
260
|
+
"links": []
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"id": "c19",
|
|
264
|
+
"kind": "requirement",
|
|
265
|
+
"text": "The adapter degrades silently and uniformly: missing [qodo] extra (ImportError), qodo-cli env/setup failure (its exit 2 \u2014 no ~/.qodo/config.json, gh absent, API error), a non-zero exit, or unparseable JSON ALL map to 'capability unavailable' \u2014 pr read/await fall back to the HTML scraper byte-for-byte, and reviewer verbs print the exit-0 unsupported notice. The adapter never raises out to the CLI.",
|
|
266
|
+
"origin": "llm",
|
|
267
|
+
"status": "confirmed",
|
|
268
|
+
"honesty_conditions": [
|
|
269
|
+
{
|
|
270
|
+
"id": "h5",
|
|
271
|
+
"text": "A test matrix exercises each degradation path \u2014 extra absent (ImportError), simulated qodo exit 2, non-zero exit, and bad JSON \u2014 and asserts: pr read/await output byte-matches the scraper snapshot, every reviewer verb exits 0 with the unsupported notice, and nothing propagates out of the adapter.",
|
|
272
|
+
"status": "confirmed"
|
|
273
|
+
}
|
|
274
|
+
],
|
|
275
|
+
"hard_questions": [],
|
|
276
|
+
"links": []
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "c20",
|
|
280
|
+
"kind": "decision",
|
|
281
|
+
"text": "Availability is detected lazily inside the adapter by attempting 'import qodo' (the [qodo] extra makes it importable). ImportError (extra absent), qodo's exit-2/non-zero surfaced as SystemExit from main(), a captured-output guard, or unparseable JSON ALL map to 'capability unavailable' \u2014 pr read/await fall back to the HTML scraper; reviewer verbs emit the exit-0 unsupported notice. The adapter never raises out to the CLI.",
|
|
282
|
+
"origin": "llm",
|
|
283
|
+
"status": "confirmed",
|
|
284
|
+
"honesty_conditions": [],
|
|
285
|
+
"hard_questions": [],
|
|
286
|
+
"links": []
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
"open_vagueness": [
|
|
290
|
+
{
|
|
291
|
+
"id": "v1",
|
|
292
|
+
"text": "Exact field names + nesting of 'qodo review list --json' (severity/type/categories/description/agent_prompt) are documented from qodo --help but NOT yet verified against live output \u2014 needs a PR carrying real Qodo bot comments + ~/.qodo/config.json. Implementation must probe the real schema and map defensively.",
|
|
293
|
+
"kind": "unknown_nonblocking",
|
|
294
|
+
"claim_id": null
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"id": "v2",
|
|
298
|
+
"text": "Whether qodo-cli reliably maps a Qodo finding to file:line the same way the scraper's permalink extraction does (so dedupe/identity stays stable across sources).",
|
|
299
|
+
"kind": "unknown_nonblocking",
|
|
300
|
+
"claim_id": null
|
|
301
|
+
}
|
|
302
|
+
]
|
|
303
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "devex-now-reads-qodo-pr-review-findings-structural",
|
|
3
|
+
"title": "devex now reads Qodo PR-review findings structurally through the installed qodo-cli instead of regex-scraping the bot's HTML comment \u2014 richer, more robust findings with a graceful fallback when qodo-cli is absent",
|
|
4
|
+
"frame_slug": "devex-now-reads-qodo-pr-review-findings-structural",
|
|
5
|
+
"schema_version": 1,
|
|
6
|
+
"status": "exported",
|
|
7
|
+
"created": "2026-06-19T08:28:26Z",
|
|
8
|
+
"updated": "2026-06-19T08:34:30Z",
|
|
9
|
+
"targets": [
|
|
10
|
+
{
|
|
11
|
+
"id": "c1",
|
|
12
|
+
"kind": "announcement",
|
|
13
|
+
"text": "devex now reads Qodo PR-review findings structurally through the installed qodo-cli instead of regex-scraping the bot's HTML comment \u2014 richer, more robust findings with a graceful fallback when qodo-cli is absent"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "h3",
|
|
17
|
+
"kind": "honesty",
|
|
18
|
+
"text": "Installing 'devex-cli[qodo]' and running 'devex pr read' on a Qodo-reviewed PR produces a strictly richer briefing than today, while an install WITHOUT the extra is byte-for-byte unchanged \u2014 proving the integration is purely additive."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "c2",
|
|
22
|
+
"kind": "audience",
|
|
23
|
+
"text": "The autonomous agent running 'devex pr read' / 'devex pr await' on an AgentCulture repo (and the human, e.g. Ori, reviewing the resulting briefing) \u2014 both currently get Qodo findings filtered through a fragile HTML scraper."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "h6",
|
|
27
|
+
"kind": "honesty",
|
|
28
|
+
"text": "grep confirms _qodo.parse is today the SOLE source of Qodo findings feeding both 'pr read' and 'pr await' (read.py + await_.py call it), so both consumers inherit any improvement to that seam."
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "c3",
|
|
32
|
+
"kind": "before_state",
|
|
33
|
+
"text": "devex extracts Qodo findings by stdlib-regex-scraping the bot's 'Code Review by Qodo' HTML comment in _qodo.py \u2014 defensive, lossy (no severity/type/categories/agent_prompt), and the historical source of a ReDoS SonarCloud hotspot."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "h7",
|
|
37
|
+
"kind": "honesty",
|
|
38
|
+
"text": "git history confirms _qodo.py parses the bot's HTML with stdlib regex and that a python:S5852 ReDoS hotspot was previously raised on a Qodo-parsing regex (commit history / SonarCloud)."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "c4",
|
|
42
|
+
"kind": "after_state",
|
|
43
|
+
"text": "When qodo-cli is on PATH, devex sources Qodo findings from 'qodo review list --json' (the tool that owns Qodo's format) \u2014 gaining per-finding severity/type/categories and self-maintaining as the format evolves \u2014 and falls back to the existing HTML scraper unchanged when qodo-cli is absent or errors."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "h8",
|
|
47
|
+
"kind": "honesty",
|
|
48
|
+
"text": "On a Qodo-reviewed PR with [qodo] installed, 'pr read' renders per-finding severity/type/categories that are absent from today's output; with the extra removed the rendered output is unchanged."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "c5",
|
|
52
|
+
"kind": "why_it_matters",
|
|
53
|
+
"text": "It moves the parsing burden onto the tool that owns the format, shrinks devex's brittle regex surface (less ReDoS/maintenance risk), and enriches the briefing \u2014 all without adding a runtime dependency or changing the default install."
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "h9",
|
|
57
|
+
"kind": "honesty",
|
|
58
|
+
"text": "After the change pyproject's runtime 'dependencies' is still [] and a test proves the qodo-cli source is preferred over the regex scraper whenever the adapter reports the capability available."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "c7",
|
|
62
|
+
"kind": "success_signal",
|
|
63
|
+
"text": "With qodo-cli installed, 'devex pr read' on a PR with Qodo findings shows the same counts/total/url as before PLUS per-finding severity/type; with qodo-cli uninstalled, output is byte-identical to today; no new failing path (any qodo-cli error degrades silently to the scraper)."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "h10",
|
|
67
|
+
"kind": "honesty",
|
|
68
|
+
"text": "Snapshot tests prove: qodo present -> briefing strictly a superset of today's; qodo absent -> output byte-identical; and no degradation path produces a non-zero exit."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "c11",
|
|
72
|
+
"kind": "requirement",
|
|
73
|
+
"text": "_qodo.parse must return the SAME {counts, total, findings, url} shape regardless of source, enriched with optional per-finding 'severity'/'type'/'categories' keys that are simply None/absent on the scraper path \u2014 so pr read / pr await templates need no branching on source."
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "h1",
|
|
77
|
+
"kind": "honesty",
|
|
78
|
+
"text": "The merged shape round-trips: a snapshot/unit test feeds a representative 'qodo review list --json' payload AND a representative HTML comment through _qodo.parse and asserts both yield the same {counts,total,findings,url} keys, with severity/type/categories present from JSON and None/absent from HTML."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "c12",
|
|
82
|
+
"kind": "requirement",
|
|
83
|
+
"text": "When qodo-cli is not installed, every existing test and every byte of 'devex pr read' / 'pr await' output is unchanged \u2014 the structured path is strictly additive and gated on qodo-cli being present AND succeeding."
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "h2",
|
|
87
|
+
"kind": "honesty",
|
|
88
|
+
"text": "A guard test simulates 'qodo' absent (which() returns None / subprocess unavailable) and asserts _qodo.parse falls back to the scraper and pr read output byte-matches the existing snapshot."
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "c14",
|
|
92
|
+
"kind": "boundary",
|
|
93
|
+
"text": "v1 ships a new 'reviewer' noun \u2014 devex's deterministic-markdown home for managing the Qodo reviewer (rules semantic-search, review-comment triage/resolve, repo reviewer config) \u2014 AND enriches existing 'pr read'/'pr await' findings, all through ONE qodo-cli adapter seam. devex wraps qodo-cli's output in its own markdown briefing + per-backend 'Next step:' footer; it never forks, vendors, or reimplements Qodo logic. When the [qodo] extra is absent every reviewer verb degrades to an exit-0 'unsupported' markdown notice (invariant #5)."
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"id": "h11",
|
|
97
|
+
"kind": "honesty",
|
|
98
|
+
"text": "devex ships NO vendored copy of qodo logic (no qodo module under src/devex); a test asserts every 'reviewer' verb exits 0 with the unsupported markdown notice when 'qodo' is unimportable."
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "c17",
|
|
102
|
+
"kind": "after_state",
|
|
103
|
+
"text": "An agent can run 'devex reviewer rules \"<q>\"', 'devex reviewer review list|resolve', and 'devex reviewer config show|validate|init' to manage Qodo entirely through devex's uniform markdown+footer surface, and 'pr read'/'pr await' gain per-finding severity/type/categories \u2014 all powered by the in-process qodo-cli adapter, with a clean unsupported-notice when the extra isn't installed."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "h12",
|
|
107
|
+
"kind": "honesty",
|
|
108
|
+
"text": "A test enumerates each 'reviewer' verb (rules / review list / review resolve / config show|validate|init) and asserts it maps to the expected 'qodo.cli.main([...])' argv through the adapter."
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "c18",
|
|
112
|
+
"kind": "requirement",
|
|
113
|
+
"text": "Invariant docs must be updated: 'reviewer review resolve' MUTATES GitHub (reply+ack+resolve), so invariant #4's side-effect set is extended to name it; and the rules/review network I/O performed inside qodo-cli (Qodo rules API + gh) is documented as an extension of the 'pr' namespace network carve-out. No new egress originates in devex itself \u2014 it all flows through the imported qodo-cli."
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"id": "h4",
|
|
117
|
+
"kind": "honesty",
|
|
118
|
+
"text": "The PR updates CLAUDE.md invariant #4 to name 'reviewer review resolve' in the side-effect set and documents the qodo-cli-mediated network egress as a pr-namespace carve-out extension; a doc/guard test or explicit review confirms devex itself opens no new socket (all network is inside the imported qodo-cli)."
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"id": "c19",
|
|
122
|
+
"kind": "requirement",
|
|
123
|
+
"text": "The adapter degrades silently and uniformly: missing [qodo] extra (ImportError), qodo-cli env/setup failure (its exit 2 \u2014 no ~/.qodo/config.json, gh absent, API error), a non-zero exit, or unparseable JSON ALL map to 'capability unavailable' \u2014 pr read/await fall back to the HTML scraper byte-for-byte, and reviewer verbs print the exit-0 unsupported notice. The adapter never raises out to the CLI."
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"id": "h5",
|
|
127
|
+
"kind": "honesty",
|
|
128
|
+
"text": "A test matrix exercises each degradation path \u2014 extra absent (ImportError), simulated qodo exit 2, non-zero exit, and bad JSON \u2014 and asserts: pr read/await output byte-matches the scraper snapshot, every reviewer verb exits 0 with the unsupported notice, and nothing propagates out of the adapter."
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
"tasks": [
|
|
132
|
+
{
|
|
133
|
+
"id": "t1",
|
|
134
|
+
"summary": "Add core/qodo.py \u2014 the single in-process qodo-cli adapter seam (import gate + main()-capture)",
|
|
135
|
+
"origin": "llm",
|
|
136
|
+
"status": "confirmed",
|
|
137
|
+
"acceptance_criteria": [
|
|
138
|
+
"available() returns False without raising when 'import qodo' fails, True when importable",
|
|
139
|
+
"run_json(argv) invokes qodo.cli.main inside redirect_stdout, catches SystemExit for the exit code, returns the parsed JSON on exit 0, and the 'unavailable' sentinel on ImportError / non-zero exit / unparseable JSON \u2014 and NEVER raises out",
|
|
140
|
+
"degradation-matrix test: ImportError, SystemExit(2), SystemExit(1), and bad-JSON all map to 'unavailable'; a valid --json payload maps to the parsed object"
|
|
141
|
+
],
|
|
142
|
+
"deps": [],
|
|
143
|
+
"covers": [
|
|
144
|
+
"c19",
|
|
145
|
+
"h5"
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "t2",
|
|
150
|
+
"summary": "Declare the optional [qodo] extra in pyproject (qodo-cli) + dev group",
|
|
151
|
+
"origin": "llm",
|
|
152
|
+
"status": "confirmed",
|
|
153
|
+
"acceptance_criteria": [
|
|
154
|
+
"[project.optional-dependencies].qodo == ['qodo-cli'] and runtime [project].dependencies is still []",
|
|
155
|
+
"a packaging test asserts dependencies==[] and that the 'qodo' extra exists and names qodo-cli"
|
|
156
|
+
],
|
|
157
|
+
"deps": [],
|
|
158
|
+
"covers": [
|
|
159
|
+
"c5"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"id": "t3",
|
|
164
|
+
"summary": "Build the 'reviewer' noun (rules / review list|resolve / config) wrapping the adapter + wire into cli.py",
|
|
165
|
+
"origin": "llm",
|
|
166
|
+
"status": "confirmed",
|
|
167
|
+
"acceptance_criteria": [
|
|
168
|
+
"each verb maps to the expected qodo argv: rules->['rules','get',q,'--json']; review list->['review','list','--json']; review resolve->['review','resolve',id,...]; config show|validate|init->['config',sub,'--json'] (enumerated mapping test)",
|
|
169
|
+
"with qodo unimportable every reviewer verb exits 0 and emits the markdown 'unsupported' notice (invariant #5); a test asserts no vendored qodo module exists under src/devex",
|
|
170
|
+
"each verb's stdout is devex markdown wrapping qodo output + a per-backend 'Next step:' footer"
|
|
171
|
+
],
|
|
172
|
+
"deps": [
|
|
173
|
+
"t1"
|
|
174
|
+
],
|
|
175
|
+
"covers": [
|
|
176
|
+
"c14",
|
|
177
|
+
"h11",
|
|
178
|
+
"c17",
|
|
179
|
+
"h12"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"id": "t4",
|
|
184
|
+
"summary": "Make _qodo.parse prefer adapter-sourced structured findings, else fall back to the HTML scraper",
|
|
185
|
+
"origin": "llm",
|
|
186
|
+
"status": "confirmed",
|
|
187
|
+
"acceptance_criteria": [
|
|
188
|
+
"round-trip shape test: a representative 'qodo review list --json' payload AND a representative HTML comment both yield {counts,total,findings,url}; severity/type/categories present from JSON, None/absent from HTML",
|
|
189
|
+
"when the adapter is unavailable, _qodo.parse falls back to the existing scraper and 'pr read' output byte-matches the pre-change snapshot",
|
|
190
|
+
"_qodo.parse stays the sole Qodo-finding source for read.py and await_.py (call sites unchanged); a test proves the qodo source is preferred whenever available"
|
|
191
|
+
],
|
|
192
|
+
"deps": [
|
|
193
|
+
"t1"
|
|
194
|
+
],
|
|
195
|
+
"covers": [
|
|
196
|
+
"c11",
|
|
197
|
+
"h1",
|
|
198
|
+
"c12",
|
|
199
|
+
"h2",
|
|
200
|
+
"c2",
|
|
201
|
+
"h6",
|
|
202
|
+
"c3",
|
|
203
|
+
"h7",
|
|
204
|
+
"h9"
|
|
205
|
+
]
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"id": "t5",
|
|
209
|
+
"summary": "Render per-finding severity/type/categories in the pr read / pr await briefing",
|
|
210
|
+
"origin": "llm",
|
|
211
|
+
"status": "confirmed",
|
|
212
|
+
"acceptance_criteria": [
|
|
213
|
+
"with structured findings present, 'pr read' renders per-finding severity/type/categories absent from today's output",
|
|
214
|
+
"snapshot tests: qodo present -> briefing is a strict superset of today's; qodo absent -> byte-identical; no degradation path returns a non-zero exit"
|
|
215
|
+
],
|
|
216
|
+
"deps": [
|
|
217
|
+
"t4"
|
|
218
|
+
],
|
|
219
|
+
"covers": [
|
|
220
|
+
"c4",
|
|
221
|
+
"h8",
|
|
222
|
+
"c7",
|
|
223
|
+
"h10",
|
|
224
|
+
"c1",
|
|
225
|
+
"h3"
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"id": "t6",
|
|
230
|
+
"summary": "Update invariant docs \u2014 CLAUDE.md #4 side-effect set + qodo-mediated network carve-out",
|
|
231
|
+
"origin": "llm",
|
|
232
|
+
"status": "confirmed",
|
|
233
|
+
"acceptance_criteria": [
|
|
234
|
+
"CLAUDE.md invariant #4 names 'reviewer review resolve' in the GitHub-mutating side-effect set",
|
|
235
|
+
"docs state the qodo-cli-mediated egress (Qodo rules API + gh) is a pr-namespace carve-out extension and that devex itself opens no new socket"
|
|
236
|
+
],
|
|
237
|
+
"deps": [],
|
|
238
|
+
"covers": [
|
|
239
|
+
"c18",
|
|
240
|
+
"h4"
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "t7",
|
|
245
|
+
"summary": "File the two follow-up issues (qodo-cli public API; devex adapter migration)",
|
|
246
|
+
"origin": "llm",
|
|
247
|
+
"status": "confirmed",
|
|
248
|
+
"acceptance_criteria": [
|
|
249
|
+
"an issue is opened on agentculture/qodo-cli requesting a documented public Python API for integration",
|
|
250
|
+
"an issue is opened on agentculture/devex to migrate the adapter from main()-capture onto that public API once it lands; both issue URLs recorded in the PR body / CHANGELOG"
|
|
251
|
+
],
|
|
252
|
+
"deps": [],
|
|
253
|
+
"covers": []
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"id": "t8",
|
|
257
|
+
"summary": "Version bump in pyproject + CHANGELOG section",
|
|
258
|
+
"origin": "llm",
|
|
259
|
+
"status": "confirmed",
|
|
260
|
+
"acceptance_criteria": [
|
|
261
|
+
"pyproject version is greater than main's (version-check passes)",
|
|
262
|
+
"CHANGELOG.md gains a new section covering the reviewer noun, the [qodo] extra, and the pr read/await enrichment"
|
|
263
|
+
],
|
|
264
|
+
"deps": [
|
|
265
|
+
"t2"
|
|
266
|
+
],
|
|
267
|
+
"covers": []
|
|
268
|
+
}
|
|
269
|
+
],
|
|
270
|
+
"risks": []
|
|
271
|
+
}
|
|
@@ -5,13 +5,23 @@ on:
|
|
|
5
5
|
branches: [main]
|
|
6
6
|
pull_request:
|
|
7
7
|
|
|
8
|
+
# Cancel superseded runs on the same ref so a rapid push sequence doesn't pile
|
|
9
|
+
# up parallel matrices (Actions-quota savings — see issue #84).
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
8
14
|
jobs:
|
|
15
|
+
# Linux-only matrix. macOS (runner ×10) and Windows (×2) were dropped to cut
|
|
16
|
+
# GitHub Actions quota — see issue #84 (devex was the org's #2 private-repo
|
|
17
|
+
# consumer; the 4 macOS legs were 65% of the quota cost from 19% of raw
|
|
18
|
+
# minutes). Trade-off: the Windows-specific guards this repo cares about
|
|
19
|
+
# (portalocker over fcntl/msvcrt; utf-8 encoding) are no longer exercised in CI.
|
|
9
20
|
test:
|
|
10
|
-
runs-on:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
11
22
|
strategy:
|
|
12
23
|
fail-fast: false
|
|
13
24
|
matrix:
|
|
14
|
-
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
15
25
|
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
16
26
|
steps:
|
|
17
27
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.30.1] - 2026-06-19
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- devex.core.qodo.MIN_PYTHON + python_supported() — the single in-code source of truth for qodo-cli's Python floor (mirrors the pyproject [qodo] marker).
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- CI: trimmed test.yml to a Linux-only matrix (was 3 OS x 4 Python, 12 jobs) and added workflow-level concurrency with cancel-in-progress to cut GitHub Actions quota (#84).
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- devex reviewer unavailable notice and its "Next step:" footer no longer recommend pip install 'devex-cli[qodo]' on Python < 3.12, where the marker-gated extra cannot install at all — they now explain the interpreter is too old and show how to recreate the environment on Python >= 3.12.
|
|
23
|
+
|
|
24
|
+
## [0.30.0] - 2026-06-19
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `reviewer` noun — devex's deterministic-markdown home for managing the Qodo reviewer through the optional sibling qodo-cli: `reviewer rules "<q>"` (semantic-search org rules), `reviewer review list` / `reviewer review resolve <id…>` (triage / reply+ack+resolve the bot's PR comments — the only mutating verb), and `reviewer config show|validate|init`. Each wraps qodo-cli's `--json` output in a devex briefing + per-backend "Next step:" footer.
|
|
29
|
+
- Optional `devex-cli[qodo]` extra (declares `qodo-cli`; runtime dependencies unchanged). qodo-cli requires Python ≥3.12, so the extra is marker-gated and is a graceful no-op on 3.10/3.11.
|
|
30
|
+
- `core/qodo.py` — the single in-process seam to qodo-cli. Binds only to the stable `qodo.cli.main(argv)` + `--json` contract (never private modules); uniformly fail-open (ImportError / exit-2 / non-zero / bad JSON all degrade to "capability unavailable"); never raises.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- `pr read` / `pr await`: when the `[qodo]` extra is installed, Qodo findings are sourced from qodo-cli's structured `review list --json` and enriched with per-finding severity/type/categories. Counts/total/url stay byte-stable from the HTML summary; without the extra the briefing is byte-identical to before. The HTML scraper remains the fallback.
|
|
35
|
+
- Docs: invariant #4 now names `reviewer review resolve` as a GitHub-mutating side effect; the qodo-cli-mediated network egress is documented as a `pr`-namespace carve-out extension (devex itself opens no new socket).
|
|
36
|
+
|
|
10
37
|
## [0.29.2] - 2026-06-13
|
|
11
38
|
|
|
12
39
|
### Changed
|