agex-cli 0.27.0__tar.gz → 0.28.0__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.
- agex_cli-0.28.0/.devague/frames/devex-now-turns-a-push-into-continuous-pr-manageme.json +259 -0
- agex_cli-0.28.0/.devague/plans/devex-now-turns-a-push-into-continuous-pr-manageme.json +216 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/CHANGELOG.md +11 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/CLAUDE.md +1 -1
- {agex_cli-0.27.0 → agex_cli-0.28.0}/PKG-INFO +1 -1
- agex_cli-0.28.0/docs/plans/2026-05-29-devex-now-turns-a-push-into-continuous-pr-manageme.md +50 -0
- agex_cli-0.28.0/docs/specs/2026-05-29-devex-now-turns-a-push-into-continuous-pr-manageme.md +67 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/pyproject.toml +1 -1
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/cli.py +48 -1
- agex_cli-0.28.0/src/devex/commands/push/SKILL.md +104 -0
- agex_cli-0.28.0/src/devex/commands/push/assets/backends/acp.yaml +7 -0
- agex_cli-0.28.0/src/devex/commands/push/assets/backends/claude-code.yaml +7 -0
- agex_cli-0.28.0/src/devex/commands/push/assets/backends/codex.yaml +7 -0
- agex_cli-0.28.0/src/devex/commands/push/assets/backends/copilot.yaml +7 -0
- agex_cli-0.28.0/src/devex/commands/push/scripts/push.py +155 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/github.py +33 -0
- agex_cli-0.28.0/tests/commands/pr/__init__.py +0 -0
- agex_cli-0.28.0/tests/commands/pr/fixtures/gh/.gitkeep +0 -0
- agex_cli-0.28.0/tests/commands/push/__init__.py +0 -0
- agex_cli-0.28.0/tests/commands/push/test_push.py +321 -0
- agex_cli-0.28.0/tests/commands/push/test_push_backends.py +112 -0
- agex_cli-0.28.0/tests/core/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_github.py +84 -0
- agex_cli-0.28.0/tests/fixtures/claude-code/empty/.gitkeep +0 -0
- agex_cli-0.28.0/tests/test_cli_dispatch.py +199 -0
- agex_cli-0.28.0/tests/test_cli_smoke.py +32 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/uv.lock +1 -1
- agex_cli-0.27.0/tests/test_cli_dispatch.py +0 -84
- agex_cli-0.27.0/tests/test_cli_smoke.py +0 -12
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/agent-config/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/agent-config/scripts/show.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/cicd/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/communicate/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/run-tests/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/sonarclaude/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/think/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/think/scripts/think.sh +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/version-bump/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.claude/skills/version-bump/scripts/bump.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.devague/frames/every-devex-command-now-closes-with-a-deterministi.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.devague/plans/every-devex-command-now-closes-with-a-deterministi.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.flake8 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.github/workflows/publish.yml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.github/workflows/test.yml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.gitignore +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/.python-version +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/LICENSE +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/README.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/culture.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/plans/2026-05-29-every-devex-command-now-closes-with-a-deterministi.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/skill-sources.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/specs/2026-05-29-every-devex-command-now-closes-with-a-deterministi.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/superpowers/plans/2026-04-18-agex-v0.1.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/superpowers/plans/2026-05-10-agex-pr.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/superpowers/specs/2026-04-18-agex-design.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/superpowers/specs/2026-04-26-agex-doctor.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/docs/superpowers/specs/2026-05-10-agex-pr-design.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/sonar-project.properties +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/__main__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/acp/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/acp/probe.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/capabilities/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/capabilities/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/capabilities/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/capabilities/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/claude_code/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/claude_code/probe.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/codex/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/codex/probe.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/copilot/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/backends/copilot/probe.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/assets/backends/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/assets/backends/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/assets/report.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/references/design.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/scripts/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/scripts/_footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/scripts/doctor.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/doctor/scripts/next_step.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/assets/backends/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/assets/backends/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/assets/topics/devex.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/references/.gitkeep +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/scripts/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/scripts/_footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/scripts/explain.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/explain/scripts/next_step.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/assets/backends/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/assets/backends/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/assets/hooks/claude-code.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/references/.gitkeep +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/scripts/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/scripts/install.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/gamify/scripts/next_step.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/assets/backends/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/assets/backends/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/assets/table.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/references/.gitkeep +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/scripts/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/scripts/_footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/scripts/next_step.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/scripts/read.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/hook/scripts/write.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/backends/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/backends/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/menu.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/cicd/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/gamify/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/gamify/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/introspect/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/introspect/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/levelup/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/levelup/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/visualize/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/assets/topics/visualize/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/references/.gitkeep +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/scripts/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/scripts/learn.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/learn/scripts/next_step.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/assets/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/assets/backends/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/assets/backends/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/assets/sections.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/references/.gitkeep +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/scripts/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/scripts/_footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/scripts/next_step.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/overview/scripts/overview.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/backends/acp.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/backends/codex.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/rules/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/rules/lint_rules.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/rules/next_step_rules.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/delta.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/lint_result.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/pr_await_detached.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/pr_briefing.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/pr_open_result.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/pr_reply_result.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/assets/templates/pr_review_result.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_await_worker.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_deploy.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_detach.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_journal.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_qodo.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_readiness.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/_sonar.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/await_.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/delta.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/lint.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/open_.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/read.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/reply.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/commands/pr/scripts/review.py +0 -0
- {agex_cli-0.27.0/src/devex/core → agex_cli-0.28.0/src/devex/commands/push}/__init__.py +0 -0
- {agex_cli-0.27.0/src/devex/core → agex_cli-0.28.0/src/devex/commands/push}/assets/__init__.py +0 -0
- {agex_cli-0.27.0/tests → agex_cli-0.28.0/src/devex/commands/push/assets/backends}/__init__.py +0 -0
- {agex_cli-0.27.0/tests/backends → agex_cli-0.28.0/src/devex/commands/push/scripts}/__init__.py +0 -0
- {agex_cli-0.27.0/tests/commands → agex_cli-0.28.0/src/devex/core}/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/_jsonl.py +0 -0
- {agex_cli-0.27.0/tests/commands/pr → agex_cli-0.28.0/src/devex/core/assets}/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/assets/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/assets/backends/neutral.yaml +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/assets/footer.md.j2 +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/backend.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/capabilities.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/config.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/hook_io.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/journal.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/paths.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/prog.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/render.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/src/devex/core/skill_loader.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tester-agents/claude/.claude/settings.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tester-agents/claude/.claude/skills +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tester-agents/claude/CLAUDE.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tester-agents/claude/README.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tester-agents/claude/culture.yaml +0 -0
- {agex_cli-0.27.0/tests/core → agex_cli-0.28.0/tests}/__init__.py +0 -0
- /agex_cli-0.27.0/tests/commands/pr/fixtures/gh/.gitkeep → /agex_cli-0.28.0/tests/backends/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/backends/test_claude_code_probe.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/backends/test_stub_probes.py +0 -0
- /agex_cli-0.27.0/tests/fixtures/claude-code/empty/.gitkeep → /agex_cli-0.28.0/tests/commands/__init__.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/fixtures/gh/pr_checks_42.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/fixtures/gh/pr_comments_42.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/fixtures/gh/qodo_summary_comment.html +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/fixtures/journals/dogfood_40.jsonl +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_await.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_await_detach.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_delta.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_deploy.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_lint.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_lint_rules.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_open.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_qodo.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_read.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_readiness.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_reply.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/pr/test_review.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/test_doctor.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/test_explain.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/test_gamify.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/test_hook.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/test_learn.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/test_overview.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/commands/test_prog_propagation.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_backend.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_capabilities.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_config.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_footer.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_hook_io.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_journal.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_paths.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_prog.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_render.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_resolve_backend.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_skill_loader.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/core/test_version_lookup.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/malformed/.claude/hooks.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/malformed/.claude/settings.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/malformed/.claude/skills/bad/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/malformed/.claude/skills/broken-yaml/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/typical/.claude/hooks.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/typical/.claude/settings.json +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/typical/.claude/skills/example/SKILL.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/fixtures/claude-code/typical/CLAUDE.md +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/test_cli_errors.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/test_footer_guarantee.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/test_footer_hints.py +0 -0
- {agex_cli-0.27.0 → agex_cli-0.28.0}/tests/test_skill_md_consistency.py +0 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "devex-now-turns-a-push-into-continuous-pr-manageme",
|
|
3
|
+
"title": "devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step \u2014 and a push to a branch with no PR stays an ordinary push.",
|
|
4
|
+
"schema_version": 1,
|
|
5
|
+
"status": "exported",
|
|
6
|
+
"created": "2026-05-29T11:17:22Z",
|
|
7
|
+
"updated": "2026-05-29T11:31:35Z",
|
|
8
|
+
"claims": [
|
|
9
|
+
{
|
|
10
|
+
"id": "c1",
|
|
11
|
+
"kind": "announcement",
|
|
12
|
+
"text": "devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step \u2014 and a push to a branch with no PR stays an ordinary push.",
|
|
13
|
+
"origin": "user",
|
|
14
|
+
"status": "confirmed",
|
|
15
|
+
"honesty_conditions": [
|
|
16
|
+
{
|
|
17
|
+
"id": "h4",
|
|
18
|
+
"text": "Shipped behavior is exactly: push current branch; if it has an open PR, enter the new-PR-style ~180s readiness wait and render the delta; else plain push + a notice.",
|
|
19
|
+
"status": "confirmed"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"hard_questions": [
|
|
23
|
+
{
|
|
24
|
+
"id": "q3",
|
|
25
|
+
"text": "Does the command also 'git commit' (commit-push) or only 'git push' already-committed work? The user is unsure ('commit-pushing / just pushing').",
|
|
26
|
+
"resolved": true,
|
|
27
|
+
"blocking": false
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"links": []
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "c2",
|
|
34
|
+
"kind": "audience",
|
|
35
|
+
"text": "An agent (or human via an agent) running devex inside a repo mid-PR, who has just committed follow-up changes on a branch that already has an open PR and wants CI/review feedback picked up automatically.",
|
|
36
|
+
"origin": "llm",
|
|
37
|
+
"status": "confirmed",
|
|
38
|
+
"honesty_conditions": [
|
|
39
|
+
{
|
|
40
|
+
"id": "h5",
|
|
41
|
+
"text": "The primary caller is an agent in an automated PR loop; the command needs no interactive input to choose the managed-vs-plain path.",
|
|
42
|
+
"status": "confirmed"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"hard_questions": [],
|
|
46
|
+
"links": []
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "c3",
|
|
50
|
+
"kind": "after_state",
|
|
51
|
+
"text": "Pushing follow-up commits to a branch with an open PR automatically enters the same review-readiness wait a new PR gets (~3-minute poll), with no separate manual 'pr await' / 'pr read --wait' step.",
|
|
52
|
+
"origin": "llm",
|
|
53
|
+
"status": "confirmed",
|
|
54
|
+
"honesty_conditions": [
|
|
55
|
+
{
|
|
56
|
+
"id": "h6",
|
|
57
|
+
"text": "Post-push triage takes zero extra commands: the wait + delta render are part of the single 'devex push' invocation.",
|
|
58
|
+
"status": "confirmed"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"hard_questions": [
|
|
62
|
+
{
|
|
63
|
+
"id": "q2",
|
|
64
|
+
"text": "Is the wait blocking the agent session (like --delayed-read) or detached (like --detached-await/await --detach)? Continuous management argues for detached + later --check.",
|
|
65
|
+
"resolved": true,
|
|
66
|
+
"blocking": false
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"links": []
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "c4",
|
|
73
|
+
"kind": "before_state",
|
|
74
|
+
"text": "Today there is no push command. After pushing, the agent must remember to manually run 'pr await' / 'pr read --wait' to re-enter triage \u2014 easy to forget, so continuous PR management silently breaks.",
|
|
75
|
+
"origin": "llm",
|
|
76
|
+
"status": "confirmed",
|
|
77
|
+
"honesty_conditions": [
|
|
78
|
+
{
|
|
79
|
+
"id": "h7",
|
|
80
|
+
"text": "Verified today: 'devex pr' has no push subcommand and no top-level push exists; re-entering triage requires a manual 'pr await' / 'pr read --wait'.",
|
|
81
|
+
"status": "confirmed"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"hard_questions": [],
|
|
85
|
+
"links": []
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "c5",
|
|
89
|
+
"kind": "why_it_matters",
|
|
90
|
+
"text": "Continuous PR management: every push, like every new PR, deterministically lands the agent back in the triage loop instead of leaving fresh CI/Sonar/review feedback unwatched.",
|
|
91
|
+
"origin": "llm",
|
|
92
|
+
"status": "confirmed",
|
|
93
|
+
"honesty_conditions": [
|
|
94
|
+
{
|
|
95
|
+
"id": "h8",
|
|
96
|
+
"text": "Determinism: identical branch/PR state always routes to the same path (managed vs plain); no backend or branch auto-detection.",
|
|
97
|
+
"status": "confirmed"
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"hard_questions": [],
|
|
101
|
+
"links": []
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"id": "c6",
|
|
105
|
+
"kind": "success_signal",
|
|
106
|
+
"text": "After a push on a PR branch, the agent ends up holding the post-push review delta (CI + Sonar + threads) without issuing a second command.",
|
|
107
|
+
"origin": "llm",
|
|
108
|
+
"status": "confirmed",
|
|
109
|
+
"honesty_conditions": [
|
|
110
|
+
{
|
|
111
|
+
"id": "h9",
|
|
112
|
+
"text": "Observable: one 'devex push' on a PR branch ends with the post-push CI/Sonar/threads delta on stdout, exit code reflecting the quality gate.",
|
|
113
|
+
"status": "confirmed"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"hard_questions": [],
|
|
117
|
+
"links": []
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "c7",
|
|
121
|
+
"kind": "boundary",
|
|
122
|
+
"text": "Not a general git porcelain: the push path is the minimum to land commits on the remote; devex does not grow into a git front-end (no rebase/merge/stash/branch management).",
|
|
123
|
+
"origin": "llm",
|
|
124
|
+
"status": "confirmed",
|
|
125
|
+
"honesty_conditions": [
|
|
126
|
+
{
|
|
127
|
+
"id": "h10",
|
|
128
|
+
"text": "Scope cap: the only git mutation devex performs is 'git push' of the current branch \u2014 no rebase/merge/stash/branch/commit.",
|
|
129
|
+
"status": "confirmed"
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"hard_questions": [],
|
|
133
|
+
"links": []
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "c8",
|
|
137
|
+
"kind": "non_goal",
|
|
138
|
+
"text": "When the branch has no open PR, devex does NOT open one \u2014 that stays an explicit 'pr open'. The push case with no PR is out of the PR-management path.",
|
|
139
|
+
"origin": "llm",
|
|
140
|
+
"status": "confirmed",
|
|
141
|
+
"honesty_conditions": [],
|
|
142
|
+
"hard_questions": [],
|
|
143
|
+
"links": []
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"id": "c9",
|
|
147
|
+
"kind": "requirement",
|
|
148
|
+
"text": "The command must detect whether the current branch has an open PR (via gh) BEFORE deciding whether to enter the wait \u2014 the PR-management path is gated on PR existence, never auto-detected away from the user's branch.",
|
|
149
|
+
"origin": "llm",
|
|
150
|
+
"status": "confirmed",
|
|
151
|
+
"honesty_conditions": [
|
|
152
|
+
{
|
|
153
|
+
"id": "h1",
|
|
154
|
+
"text": "Open-PR detection is a single 'gh pr view --json' style call on the current branch; no PR => exit 0 with a plain-push (or notice) path, never an error.",
|
|
155
|
+
"status": "confirmed"
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"hard_questions": [],
|
|
159
|
+
"links": []
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "c10",
|
|
163
|
+
"kind": "requirement",
|
|
164
|
+
"text": "The default post-push wait is ~180s (3 minutes), matching 'pr open --delayed-read' (pr read --wait 180), not pr await's 1800s default \u2014 overridable via a flag.",
|
|
165
|
+
"origin": "llm",
|
|
166
|
+
"status": "confirmed",
|
|
167
|
+
"honesty_conditions": [
|
|
168
|
+
{
|
|
169
|
+
"id": "h2",
|
|
170
|
+
"text": "The 180s default is exposed as an overridable flag (e.g. --max-wait) and documented as matching the new-PR delayed read.",
|
|
171
|
+
"status": "confirmed"
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
"hard_questions": [],
|
|
175
|
+
"links": []
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"id": "c11",
|
|
179
|
+
"kind": "decision",
|
|
180
|
+
"text": "The command lives under the existing 'pr' namespace as 'devex pr push' (continuous PR management is a pr concern), rather than a top-level 'devex push'.",
|
|
181
|
+
"origin": "llm",
|
|
182
|
+
"status": "rejected",
|
|
183
|
+
"honesty_conditions": [],
|
|
184
|
+
"hard_questions": [
|
|
185
|
+
{
|
|
186
|
+
"id": "q1",
|
|
187
|
+
"text": "risk: Naming as 'pr push' is odd when no PR exists (you'd 'pr push' a branch that has no PR) \u2014 top-level 'devex push' may read better for the plain-push case.",
|
|
188
|
+
"resolved": true,
|
|
189
|
+
"blocking": false
|
|
190
|
+
}
|
|
191
|
+
],
|
|
192
|
+
"links": []
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"id": "c12",
|
|
196
|
+
"kind": "assumption",
|
|
197
|
+
"text": "It reuses the existing readiness machinery \u2014 pr await --detach/--check and/or pr read --wait \u2014 rather than introducing a second poller implementation.",
|
|
198
|
+
"origin": "llm",
|
|
199
|
+
"status": "confirmed",
|
|
200
|
+
"honesty_conditions": [],
|
|
201
|
+
"hard_questions": [],
|
|
202
|
+
"links": []
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"id": "c13",
|
|
206
|
+
"kind": "requirement",
|
|
207
|
+
"text": "Performing 'git push' of the current branch is a NEW class of side effect for devex (push-only; no commit); it requires an explicit carve-out added to design-invariant #4, alongside the existing pr-namespace network/sleep exceptions.",
|
|
208
|
+
"origin": "llm",
|
|
209
|
+
"status": "confirmed",
|
|
210
|
+
"honesty_conditions": [
|
|
211
|
+
{
|
|
212
|
+
"id": "h3",
|
|
213
|
+
"text": "design-invariant #4 in CLAUDE.md is amended to name 'git push' as an allowed side effect of 'devex push', with the same explicitness as the existing gh/sleep carve-out \u2014 otherwise the feature violates a non-negotiable invariant.",
|
|
214
|
+
"status": "confirmed"
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
"hard_questions": [],
|
|
218
|
+
"links": []
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"id": "c14",
|
|
222
|
+
"kind": "decision",
|
|
223
|
+
"text": "Top-level 'devex push' (not 'devex pr push'): reads naturally for the no-PR 'just push' case and conditionally enters PR management when an open PR exists.",
|
|
224
|
+
"origin": "llm",
|
|
225
|
+
"status": "confirmed",
|
|
226
|
+
"honesty_conditions": [],
|
|
227
|
+
"hard_questions": [],
|
|
228
|
+
"links": []
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"id": "c15",
|
|
232
|
+
"kind": "decision",
|
|
233
|
+
"text": "Push-only: pushes already-committed work; devex does NOT stage or commit. Commit-push is out of scope for v0.1.",
|
|
234
|
+
"origin": "llm",
|
|
235
|
+
"status": "confirmed",
|
|
236
|
+
"honesty_conditions": [],
|
|
237
|
+
"hard_questions": [],
|
|
238
|
+
"links": []
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": "c16",
|
|
242
|
+
"kind": "decision",
|
|
243
|
+
"text": "After-push wait is BLOCKING ~180s (mirrors 'pr open --delayed-read' = 'pr read --wait 180'), not detached; --max-wait overrides. Resolves q2.",
|
|
244
|
+
"origin": "llm",
|
|
245
|
+
"status": "confirmed",
|
|
246
|
+
"honesty_conditions": [],
|
|
247
|
+
"hard_questions": [],
|
|
248
|
+
"links": []
|
|
249
|
+
}
|
|
250
|
+
],
|
|
251
|
+
"open_vagueness": [
|
|
252
|
+
{
|
|
253
|
+
"id": "v1",
|
|
254
|
+
"text": "RESOLVED (push-only, c15): commit-push (stage+commit) is out of scope for v0.1; 'devex push' strictly pushes already-committed work.",
|
|
255
|
+
"kind": "out_of_scope",
|
|
256
|
+
"claim_id": "c15"
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "devex-now-turns-a-push-into-continuous-pr-manageme",
|
|
3
|
+
"title": "devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step \u2014 and a push to a branch with no PR stays an ordinary push.",
|
|
4
|
+
"frame_slug": "devex-now-turns-a-push-into-continuous-pr-manageme",
|
|
5
|
+
"schema_version": 1,
|
|
6
|
+
"status": "exported",
|
|
7
|
+
"created": "2026-05-29T11:35:28Z",
|
|
8
|
+
"updated": "2026-05-29T11:52:00Z",
|
|
9
|
+
"targets": [
|
|
10
|
+
{
|
|
11
|
+
"id": "c1",
|
|
12
|
+
"kind": "announcement",
|
|
13
|
+
"text": "devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step \u2014 and a push to a branch with no PR stays an ordinary push."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "h4",
|
|
17
|
+
"kind": "honesty",
|
|
18
|
+
"text": "Shipped behavior is exactly: push current branch; if it has an open PR, enter the new-PR-style ~180s readiness wait and render the delta; else plain push + a notice."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "c2",
|
|
22
|
+
"kind": "audience",
|
|
23
|
+
"text": "An agent (or human via an agent) running devex inside a repo mid-PR, who has just committed follow-up changes on a branch that already has an open PR and wants CI/review feedback picked up automatically."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "h5",
|
|
27
|
+
"kind": "honesty",
|
|
28
|
+
"text": "The primary caller is an agent in an automated PR loop; the command needs no interactive input to choose the managed-vs-plain path."
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "c3",
|
|
32
|
+
"kind": "after_state",
|
|
33
|
+
"text": "Pushing follow-up commits to a branch with an open PR automatically enters the same review-readiness wait a new PR gets (~3-minute poll), with no separate manual 'pr await' / 'pr read --wait' step."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "h6",
|
|
37
|
+
"kind": "honesty",
|
|
38
|
+
"text": "Post-push triage takes zero extra commands: the wait + delta render are part of the single 'devex push' invocation."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "c4",
|
|
42
|
+
"kind": "before_state",
|
|
43
|
+
"text": "Today there is no push command. After pushing, the agent must remember to manually run 'pr await' / 'pr read --wait' to re-enter triage \u2014 easy to forget, so continuous PR management silently breaks."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "h7",
|
|
47
|
+
"kind": "honesty",
|
|
48
|
+
"text": "Verified today: 'devex pr' has no push subcommand and no top-level push exists; re-entering triage requires a manual 'pr await' / 'pr read --wait'."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "c5",
|
|
52
|
+
"kind": "why_it_matters",
|
|
53
|
+
"text": "Continuous PR management: every push, like every new PR, deterministically lands the agent back in the triage loop instead of leaving fresh CI/Sonar/review feedback unwatched."
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "h8",
|
|
57
|
+
"kind": "honesty",
|
|
58
|
+
"text": "Determinism: identical branch/PR state always routes to the same path (managed vs plain); no backend or branch auto-detection."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "c6",
|
|
62
|
+
"kind": "success_signal",
|
|
63
|
+
"text": "After a push on a PR branch, the agent ends up holding the post-push review delta (CI + Sonar + threads) without issuing a second command."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "h9",
|
|
67
|
+
"kind": "honesty",
|
|
68
|
+
"text": "Observable: one 'devex push' on a PR branch ends with the post-push CI/Sonar/threads delta on stdout, exit code reflecting the quality gate."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "c7",
|
|
72
|
+
"kind": "boundary",
|
|
73
|
+
"text": "Not a general git porcelain: the push path is the minimum to land commits on the remote; devex does not grow into a git front-end (no rebase/merge/stash/branch management)."
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "h10",
|
|
77
|
+
"kind": "honesty",
|
|
78
|
+
"text": "Scope cap: the only git mutation devex performs is 'git push' of the current branch \u2014 no rebase/merge/stash/branch/commit."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "c9",
|
|
82
|
+
"kind": "requirement",
|
|
83
|
+
"text": "The command must detect whether the current branch has an open PR (via gh) BEFORE deciding whether to enter the wait \u2014 the PR-management path is gated on PR existence, never auto-detected away from the user's branch."
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "h1",
|
|
87
|
+
"kind": "honesty",
|
|
88
|
+
"text": "Open-PR detection is a single 'gh pr view --json' style call on the current branch; no PR => exit 0 with a plain-push (or notice) path, never an error."
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "c10",
|
|
92
|
+
"kind": "requirement",
|
|
93
|
+
"text": "The default post-push wait is ~180s (3 minutes), matching 'pr open --delayed-read' (pr read --wait 180), not pr await's 1800s default \u2014 overridable via a flag."
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"id": "h2",
|
|
97
|
+
"kind": "honesty",
|
|
98
|
+
"text": "The 180s default is exposed as an overridable flag (e.g. --max-wait) and documented as matching the new-PR delayed read."
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "c13",
|
|
102
|
+
"kind": "requirement",
|
|
103
|
+
"text": "Performing 'git push' of the current branch is a NEW class of side effect for devex (push-only; no commit); it requires an explicit carve-out added to design-invariant #4, alongside the existing pr-namespace network/sleep exceptions."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "h3",
|
|
107
|
+
"kind": "honesty",
|
|
108
|
+
"text": "design-invariant #4 in CLAUDE.md is amended to name 'git push' as an allowed side effect of 'devex push', with the same explicitness as the existing gh/sleep carve-out \u2014 otherwise the feature violates a non-negotiable invariant."
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"tasks": [
|
|
112
|
+
{
|
|
113
|
+
"id": "t1",
|
|
114
|
+
"summary": "core/github.py: add git_push() and current_branch_pr() primitives (push-only; single gh pr view for PR detection)",
|
|
115
|
+
"origin": "llm",
|
|
116
|
+
"status": "confirmed",
|
|
117
|
+
"acceptance_criteria": [
|
|
118
|
+
"git_push() runs exactly 'git push' of the current branch and nothing else (no commit/rebase/merge/stash/branch); unit test mocks the subprocess, asserts the git argv, and asserts a push failure surfaces as a raised/non-zero error.",
|
|
119
|
+
"current_branch_pr() returns the open PR number for the current branch via a single 'gh pr view --json' call, or None when there is no PR \u2014 never raises on the no-PR case; unit test mocks gh for both branches."
|
|
120
|
+
],
|
|
121
|
+
"deps": [],
|
|
122
|
+
"covers": [
|
|
123
|
+
"c9",
|
|
124
|
+
"h1",
|
|
125
|
+
"c7",
|
|
126
|
+
"h10",
|
|
127
|
+
"c13"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": "t2",
|
|
132
|
+
"summary": "docs: amend design-invariant #4 in CLAUDE.md to allow 'git push' as a 'devex push' side effect",
|
|
133
|
+
"origin": "llm",
|
|
134
|
+
"status": "confirmed",
|
|
135
|
+
"acceptance_criteria": [
|
|
136
|
+
"design-invariant #4 in CLAUDE.md names 'git push' (push-only) as an allowed side effect of 'devex push', listed alongside the existing pr-namespace gh/sleep carve-outs; the side-effects list and the prose are mutually consistent (no other invariant weakened)."
|
|
137
|
+
],
|
|
138
|
+
"deps": [],
|
|
139
|
+
"covers": [
|
|
140
|
+
"c13",
|
|
141
|
+
"h3"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"id": "t3",
|
|
146
|
+
"summary": "commands/push/: devex push command \u2014 git_push, detect open PR, route to blocking ~180s wait+delta (PR exists) or plain push + notice (no PR)",
|
|
147
|
+
"origin": "llm",
|
|
148
|
+
"status": "confirmed",
|
|
149
|
+
"acceptance_criteria": [
|
|
150
|
+
"With an open PR on the current branch, 'devex push' calls git_push then enters the existing pr read/await wait (default 180s) and renders the CI/Sonar/threads delta in ONE invocation; integration test (gh+git mocked) asserts no second command and the delta on stdout.",
|
|
151
|
+
"With no open PR, 'devex push' calls git_push then prints the deterministic 'no PR on this branch \u2014 open one with devex pr open' notice and exits 0; test asserts exit 0, the notice text, and that NO wait occurs.",
|
|
152
|
+
"Routing is deterministic on (current branch, PR-exists) with no backend/branch auto-detection \u2014 same inputs always select the same path (test).",
|
|
153
|
+
"On the managed path the exit code reflects the post-wait quality gate (non-zero on gate ERROR / unresolved threads), mirroring pr await (test)."
|
|
154
|
+
],
|
|
155
|
+
"deps": [
|
|
156
|
+
"t1"
|
|
157
|
+
],
|
|
158
|
+
"covers": [
|
|
159
|
+
"c1",
|
|
160
|
+
"h4",
|
|
161
|
+
"c3",
|
|
162
|
+
"h6",
|
|
163
|
+
"c5",
|
|
164
|
+
"h8",
|
|
165
|
+
"c6",
|
|
166
|
+
"h9"
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"id": "t4",
|
|
171
|
+
"summary": "cli.py: register top-level 'devex push' subcommand with --max-wait (default 180) and --agent",
|
|
172
|
+
"origin": "llm",
|
|
173
|
+
"status": "confirmed",
|
|
174
|
+
"acceptance_criteria": [
|
|
175
|
+
"'devex --help' lists 'push'; 'devex push --help' shows --max-wait (default 180) and --agent; parsing dispatches to the push command entry (test).",
|
|
176
|
+
"--max-wait overrides the 180s default and is threaded into the wait; the default equals pr open --delayed-read's 180 (test asserts the value reaches the wait call).",
|
|
177
|
+
"The command takes no interactive input \u2014 all inputs arrive via argv/flags; runs non-interactively to completion (test)."
|
|
178
|
+
],
|
|
179
|
+
"deps": [
|
|
180
|
+
"t3"
|
|
181
|
+
],
|
|
182
|
+
"covers": [
|
|
183
|
+
"c4",
|
|
184
|
+
"h7",
|
|
185
|
+
"c10",
|
|
186
|
+
"h2",
|
|
187
|
+
"c2",
|
|
188
|
+
"h5"
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"id": "t5",
|
|
193
|
+
"summary": "commands/push/assets/backends/{claude-code,codex,copilot,acp}.yaml: per-backend next-step phrasing for the no-PR notice and the post-wait delta",
|
|
194
|
+
"origin": "llm",
|
|
195
|
+
"status": "confirmed",
|
|
196
|
+
"acceptance_criteria": [
|
|
197
|
+
"All four backends have a push asset with deterministic next-step phrasing for both the no-PR notice and the post-wait delta; test asserts all four load and render with no StrictUndefined errors (all-backends rule)."
|
|
198
|
+
],
|
|
199
|
+
"deps": [
|
|
200
|
+
"t3"
|
|
201
|
+
],
|
|
202
|
+
"covers": [
|
|
203
|
+
"c2",
|
|
204
|
+
"h5"
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
"risks": [
|
|
209
|
+
{
|
|
210
|
+
"id": "r1",
|
|
211
|
+
"text": "Reusing pr read/await's wait+delta from the new command (t3) may need a shared helper extracted out of commands/pr/scripts if the logic isn't cleanly importable \u2014 could widen t3's file scope into commands/pr.",
|
|
212
|
+
"kind": "unknown_nonblocking",
|
|
213
|
+
"task_id": "t3"
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
}
|
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.28.0] - 2026-05-29
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `devex push` — a top-level command that pushes the current branch, then enters continuous PR management: if the branch has an open PR it runs the same gate-aware readiness wait `pr await` does (default 180s, `--max-wait` overrides) and renders the CI/SonarCloud/threads delta in one invocation; with no open PR it does a plain push and prints a deterministic notice pointing at `pr open`. Push-only (never stages or commits). Per-backend next-step phrasing for all four backends.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- design-invariant #4 now names `git push` (push-only) as an allowed side effect of `devex push`, alongside the existing pr-namespace gh/sleep carve-outs.
|
|
19
|
+
- `core/github.py` gains `git_push()` and `current_branch_pr()` helpers.
|
|
20
|
+
|
|
10
21
|
## [0.27.0] - 2026-05-29
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -19,7 +19,7 @@ Read the spec before any non-trivial change — the design invariants below are
|
|
|
19
19
|
1. **Zero LLM calls inside devex.** All output is deterministic markdown from Jinja templates + Python.
|
|
20
20
|
2. **Markdown is the only output format.** No `--json` flag.
|
|
21
21
|
3. **`--agent <backend>` is required** on backend-sensitive commands. The CLI never auto-detects.
|
|
22
|
-
4. **Side effects only in** `gamify`, `gamify --uninstall`, `hook write`, `pr open`, `pr reply`, `pr review`, `pr read` (journal writes), `pr await` (journal + `--detach` marker writes under `.devex/data/pr/<pr>/` and the detached poller subprocess), and first-run `.devex/` init. Everything else is read-only. The `devex pr` namespace allows scoped network I/O (via `gh`), bounded `--wait` sleep, and — for `pr await --detach` — a detached background process that pays that sleep outside the agent session; a deliberate carve-out from the no-network/no-sleep invariants.
|
|
22
|
+
4. **Side effects only in** `gamify`, `gamify --uninstall`, `hook write`, `pr open`, `pr reply`, `pr review`, `pr read` (journal writes), `pr await` (journal + `--detach` marker writes under `.devex/data/pr/<pr>/` and the detached poller subprocess), `push` (see below), and first-run `.devex/` init. Everything else is read-only. The `devex pr` namespace allows scoped network I/O (via `gh`), bounded `--wait` sleep, and — for `pr await --detach` — a detached background process that pays that sleep outside the agent session; a deliberate carve-out from the no-network/no-sleep invariants. `devex push` performs a `git push` of the current branch (push-only — it never stages or commits); a deliberate carve-out from the no-mutation invariant, introducing `git push` as a new allowed side-effect class.
|
|
23
23
|
5. **"Unsupported" is success** — exit 0 with a markdown notice that links to the issue tracker, not a non-zero exit.
|
|
24
24
|
6. **Skills are authored by the agent, not shipped by devex.** `devex learn <topic>` teaches; `devex explain <topic>` describes; devex never writes a user skill file on the agent's behalf in v0.1.
|
|
25
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agex-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.28.0
|
|
4
4
|
Summary: Agent-operated developer-experience CLI — deterministic per-backend markdown briefings for autonomous agents.
|
|
5
5
|
Project-URL: Homepage, https://culture.dev/devex/
|
|
6
6
|
Project-URL: Repository, https://github.com/agentculture/devex
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Build Plan — devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step — and a push to a branch with no PR stays an ordinary push.
|
|
2
|
+
|
|
3
|
+
slug: `devex-now-turns-a-push-into-continuous-pr-manageme` · status: `exported` · from frame: `devex-now-turns-a-push-into-continuous-pr-manageme`
|
|
4
|
+
|
|
5
|
+
> devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step — and a push to a branch with no PR stays an ordinary push.
|
|
6
|
+
|
|
7
|
+
## Tasks
|
|
8
|
+
|
|
9
|
+
### t1 — core/github.py: add git_push() and current_branch_pr() primitives (push-only; single gh pr view for PR detection)
|
|
10
|
+
|
|
11
|
+
- covers: c9, h1, c7, h10, c13
|
|
12
|
+
- acceptance:
|
|
13
|
+
- git_push() runs exactly 'git push' of the current branch and nothing else (no commit/rebase/merge/stash/branch); unit test mocks the subprocess, asserts the git argv, and asserts a push failure surfaces as a raised/non-zero error.
|
|
14
|
+
- current_branch_pr() returns the open PR number for the current branch via a single 'gh pr view --json' call, or None when there is no PR — never raises on the no-PR case; unit test mocks gh for both branches.
|
|
15
|
+
|
|
16
|
+
### t2 — docs: amend design-invariant #4 in CLAUDE.md to allow 'git push' as a 'devex push' side effect
|
|
17
|
+
|
|
18
|
+
- covers: c13, h3
|
|
19
|
+
- acceptance:
|
|
20
|
+
- design-invariant #4 in CLAUDE.md names 'git push' (push-only) as an allowed side effect of 'devex push', listed alongside the existing pr-namespace gh/sleep carve-outs; the side-effects list and the prose are mutually consistent (no other invariant weakened).
|
|
21
|
+
|
|
22
|
+
### t3 — commands/push/: devex push command — git_push, detect open PR, route to blocking ~180s wait+delta (PR exists) or plain push + notice (no PR)
|
|
23
|
+
|
|
24
|
+
- depends on: t1
|
|
25
|
+
- covers: c1, h4, c3, h6, c5, h8, c6, h9
|
|
26
|
+
- acceptance:
|
|
27
|
+
- With an open PR on the current branch, 'devex push' calls git_push then enters the existing pr read/await wait (default 180s) and renders the CI/Sonar/threads delta in ONE invocation; integration test (gh+git mocked) asserts no second command and the delta on stdout.
|
|
28
|
+
- With no open PR, 'devex push' calls git_push then prints the deterministic 'no PR on this branch — open one with devex pr open' notice and exits 0; test asserts exit 0, the notice text, and that NO wait occurs.
|
|
29
|
+
- Routing is deterministic on (current branch, PR-exists) with no backend/branch auto-detection — same inputs always select the same path (test).
|
|
30
|
+
- On the managed path the exit code reflects the post-wait quality gate (non-zero on gate ERROR / unresolved threads), mirroring pr await (test).
|
|
31
|
+
|
|
32
|
+
### t4 — cli.py: register top-level 'devex push' subcommand with --max-wait (default 180) and --agent
|
|
33
|
+
|
|
34
|
+
- depends on: t3
|
|
35
|
+
- covers: c4, h7, c10, h2, c2, h5
|
|
36
|
+
- acceptance:
|
|
37
|
+
- 'devex --help' lists 'push'; 'devex push --help' shows --max-wait (default 180) and --agent; parsing dispatches to the push command entry (test).
|
|
38
|
+
- --max-wait overrides the 180s default and is threaded into the wait; the default equals pr open --delayed-read's 180 (test asserts the value reaches the wait call).
|
|
39
|
+
- The command takes no interactive input — all inputs arrive via argv/flags; runs non-interactively to completion (test).
|
|
40
|
+
|
|
41
|
+
### t5 — commands/push/assets/backends/{claude-code,codex,copilot,acp}.yaml: per-backend next-step phrasing for the no-PR notice and the post-wait delta
|
|
42
|
+
|
|
43
|
+
- depends on: t3
|
|
44
|
+
- covers: c2, h5
|
|
45
|
+
- acceptance:
|
|
46
|
+
- All four backends have a push asset with deterministic next-step phrasing for both the no-PR notice and the post-wait delta; test asserts all four load and render with no StrictUndefined errors (all-backends rule).
|
|
47
|
+
|
|
48
|
+
## Risks
|
|
49
|
+
|
|
50
|
+
- [unknown_nonblocking] Reusing pr read/await's wait+delta from the new command (t3) may need a shared helper extracted out of commands/pr/scripts if the logic isn't cleanly importable — could widen t3's file scope into commands/pr. (task t3)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step — and a push to a branch with no PR stays an ordinary push.
|
|
2
|
+
|
|
3
|
+
> devex now turns a push into continuous PR management: when you push commits to a branch that already has an open PR, devex automatically enters the same review-readiness wait a new PR gets (the ~3-minute poll), so follow-up commits get triaged without a manual step — and a push to a branch with no PR stays an ordinary push.
|
|
4
|
+
|
|
5
|
+
## Audience
|
|
6
|
+
|
|
7
|
+
- An agent (or human via an agent) running devex inside a repo mid-PR, who has just committed follow-up changes on a branch that already has an open PR and wants CI/review feedback picked up automatically.
|
|
8
|
+
|
|
9
|
+
## Before → After
|
|
10
|
+
|
|
11
|
+
- Before: Today there is no push command. After pushing, the agent must remember to manually run 'pr await' / 'pr read --wait' to re-enter triage — easy to forget, so continuous PR management silently breaks.
|
|
12
|
+
- After: Pushing follow-up commits to a branch with an open PR automatically enters the same review-readiness wait a new PR gets (~3-minute poll), with no separate manual 'pr await' / 'pr read --wait' step.
|
|
13
|
+
|
|
14
|
+
## Why it matters
|
|
15
|
+
|
|
16
|
+
- Continuous PR management: every push, like every new PR, deterministically lands the agent back in the triage loop instead of leaving fresh CI/Sonar/review feedback unwatched.
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- The command must detect whether the current branch has an open PR (via gh) BEFORE deciding whether to enter the wait — the PR-management path is gated on PR existence, never auto-detected away from the user's branch.
|
|
21
|
+
- honesty: Open-PR detection is a single 'gh pr view --json' style call on the current branch; no PR => exit 0 with a plain-push (or notice) path, never an error.
|
|
22
|
+
- The default post-push wait is ~180s (3 minutes), matching 'pr open --delayed-read' (pr read --wait 180), not pr await's 1800s default — overridable via a flag.
|
|
23
|
+
- honesty: The 180s default is exposed as an overridable flag (e.g. --max-wait) and documented as matching the new-PR delayed read.
|
|
24
|
+
- Performing 'git push' of the current branch is a NEW class of side effect for devex (push-only; no commit); it requires an explicit carve-out added to design-invariant #4, alongside the existing pr-namespace network/sleep exceptions.
|
|
25
|
+
- honesty: design-invariant #4 in CLAUDE.md is amended to name 'git push' as an allowed side effect of 'devex push', with the same explicitness as the existing gh/sleep carve-out — otherwise the feature violates a non-negotiable invariant.
|
|
26
|
+
|
|
27
|
+
## Honesty conditions
|
|
28
|
+
|
|
29
|
+
- Shipped behavior is exactly: push current branch; if it has an open PR, enter the new-PR-style ~180s readiness wait and render the delta; else plain push + a notice.
|
|
30
|
+
- The primary caller is an agent in an automated PR loop; the command needs no interactive input to choose the managed-vs-plain path.
|
|
31
|
+
- Post-push triage takes zero extra commands: the wait + delta render are part of the single 'devex push' invocation.
|
|
32
|
+
- Verified today: 'devex pr' has no push subcommand and no top-level push exists; re-entering triage requires a manual 'pr await' / 'pr read --wait'.
|
|
33
|
+
- Determinism: identical branch/PR state always routes to the same path (managed vs plain); no backend or branch auto-detection.
|
|
34
|
+
- Observable: one 'devex push' on a PR branch ends with the post-push CI/Sonar/threads delta on stdout, exit code reflecting the quality gate.
|
|
35
|
+
- Scope cap: the only git mutation devex performs is 'git push' of the current branch — no rebase/merge/stash/branch/commit.
|
|
36
|
+
|
|
37
|
+
## Success signals
|
|
38
|
+
|
|
39
|
+
- After a push on a PR branch, the agent ends up holding the post-push review delta (CI + Sonar + threads) without issuing a second command.
|
|
40
|
+
|
|
41
|
+
## Scope / boundaries
|
|
42
|
+
|
|
43
|
+
- Not a general git porcelain: the push path is the minimum to land commits on the remote; devex does not grow into a git front-end (no rebase/merge/stash/branch management).
|
|
44
|
+
|
|
45
|
+
## Non-goals
|
|
46
|
+
|
|
47
|
+
- When the branch has no open PR, devex does NOT open one — that stays an explicit 'pr open'. The push case with no PR is out of the PR-management path.
|
|
48
|
+
|
|
49
|
+
## Assumptions
|
|
50
|
+
|
|
51
|
+
- It reuses the existing readiness machinery — pr await --detach/--check and/or pr read --wait — rather than introducing a second poller implementation.
|
|
52
|
+
|
|
53
|
+
## Decisions
|
|
54
|
+
|
|
55
|
+
- Top-level 'devex push' (not 'devex pr push'): reads naturally for the no-PR 'just push' case and conditionally enters PR management when an open PR exists.
|
|
56
|
+
- Push-only: pushes already-committed work; devex does NOT stage or commit. Commit-push is out of scope for v0.1.
|
|
57
|
+
- After-push wait is BLOCKING ~180s (mirrors 'pr open --delayed-read' = 'pr read --wait 180'), not detached; --max-wait overrides. Resolves q2.
|
|
58
|
+
|
|
59
|
+
## Hard questions
|
|
60
|
+
|
|
61
|
+
- Does the command also 'git commit' (commit-push) or only 'git push' already-committed work? The user is unsure ('commit-pushing / just pushing').
|
|
62
|
+
- Is the wait blocking the agent session (like --delayed-read) or detached (like --detached-await/await --detach)? Continuous management argues for detached + later --check.
|
|
63
|
+
- risk: Naming as 'pr push' is odd when no PR exists (you'd 'pr push' a branch that has no PR) — top-level 'devex push' may read better for the plain-push case.
|
|
64
|
+
|
|
65
|
+
## Open / follow-up
|
|
66
|
+
|
|
67
|
+
- RESOLVED (push-only, c15): commit-push (stage+commit) is out of scope for v0.1; 'devex push' strictly pushes already-committed work.
|