agex-cli 0.22.0__tar.gz → 0.23.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.22.0 → agex_cli-0.23.0}/.github/workflows/publish.yml +19 -13
- {agex_cli-0.22.0 → agex_cli-0.23.0}/CHANGELOG.md +17 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/CLAUDE.md +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/PKG-INFO +6 -6
- agex_cli-0.23.0/README.md +29 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/pyproject.toml +4 -3
- {agex_cli-0.22.0 → agex_cli-0.23.0}/sonar-project.properties +2 -2
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/__init__.py +8 -7
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/cli.py +23 -15
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/doctor/assets/report.md.j2 +2 -2
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/doctor/scripts/doctor.py +12 -9
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/explain/assets/topics/agex.md +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/explain/scripts/explain.py +2 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/gamify/scripts/install.py +7 -5
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/hook/scripts/write.py +2 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/menu.md.j2 +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/scripts/learn.py +3 -2
- agex_cli-0.23.0/src/agent_experience/commands/pr/assets/backends/acp.yaml +20 -0
- agex_cli-0.23.0/src/agent_experience/commands/pr/assets/backends/claude-code.yaml +20 -0
- agex_cli-0.23.0/src/agent_experience/commands/pr/assets/backends/codex.yaml +20 -0
- agex_cli-0.23.0/src/agent_experience/commands/pr/assets/backends/copilot.yaml +20 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/templates/delta.md.j2 +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/templates/lint_result.md.j2 +2 -2
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/templates/pr_briefing.md.j2 +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/templates/pr_open_result.md.j2 +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/templates/pr_reply_result.md.j2 +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/_readiness.py +5 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/delta.py +4 -2
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/reply.py +6 -4
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/capabilities.py +1 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/hook_io.py +1 -1
- agex_cli-0.23.0/src/agent_experience/core/prog.py +44 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/render.py +9 -1
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_footer.py +16 -0
- agex_cli-0.23.0/tests/commands/test_prog_propagation.py +45 -0
- agex_cli-0.23.0/tests/core/test_prog.py +39 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_version_lookup.py +13 -6
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/test_cli_dispatch.py +11 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/uv.lock +1 -1
- agex_cli-0.22.0/README.md +0 -29
- agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/acp.yaml +0 -20
- agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/claude-code.yaml +0 -20
- agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/codex.yaml +0 -20
- agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/copilot.yaml +0 -20
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/agent-config/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/agent-config/scripts/show.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/cicd/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/communicate/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/run-tests/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/sonarclaude/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/think/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/think/scripts/think.sh +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/version-bump/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.claude/skills/version-bump/scripts/bump.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.flake8 +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.github/workflows/test.yml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.gitignore +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/.python-version +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/LICENSE +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/culture.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/docs/skill-sources.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/docs/superpowers/plans/2026-04-18-agex-v0.1.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/docs/superpowers/plans/2026-05-10-agex-pr.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/docs/superpowers/specs/2026-04-18-agex-design.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/docs/superpowers/specs/2026-04-26-agex-doctor.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/docs/superpowers/specs/2026-05-10-agex-pr-design.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/__main__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/acp/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/acp/probe.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/capabilities/acp.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/capabilities/claude-code.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/capabilities/codex.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/capabilities/copilot.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/claude_code/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/claude_code/probe.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/codex/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/codex/probe.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/copilot/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/backends/copilot/probe.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/doctor/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/doctor/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/doctor/references/design.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/doctor/scripts/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/explain/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/explain/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/explain/references/.gitkeep +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/explain/scripts/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/gamify/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/gamify/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/gamify/assets/hooks/claude-code.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/gamify/references/.gitkeep +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/gamify/scripts/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/hook/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/hook/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/hook/assets/table.md.j2 +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/hook/references/.gitkeep +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/hook/scripts/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/hook/scripts/read.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/cicd/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/gamify/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/gamify/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/introspect/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/introspect/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/levelup/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/levelup/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/visualize/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/assets/topics/visualize/assets/skill-template/claude-code/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/references/.gitkeep +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/learn/scripts/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/assets/backends/acp.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/assets/backends/claude-code.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/assets/backends/codex.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/assets/backends/copilot.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/assets/sections.md.j2 +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/references/.gitkeep +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/scripts/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/overview/scripts/overview.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/backends/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/rules/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/rules/lint_rules.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/rules/next_step_rules.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/templates/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/assets/templates/footer.md.j2 +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/_footer.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/_journal.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/_qodo.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/_sonar.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/await_.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/lint.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/open_.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/pr/scripts/read.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/backend.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/config.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/github.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/journal.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/paths.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/core/skill_loader.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tester-agents/claude/.claude/settings.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tester-agents/claude/CLAUDE.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tester-agents/claude/README.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tester-agents/claude/culture.yaml +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/backends/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/backends/test_claude_code_probe.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/backends/test_stub_probes.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/fixtures/gh/.gitkeep +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/fixtures/gh/pr_checks_42.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/fixtures/gh/pr_comments_42.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/fixtures/gh/qodo_summary_comment.html +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/fixtures/journals/dogfood_40.jsonl +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_await.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_delta.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_lint.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_lint_rules.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_open.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_qodo.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_read.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/pr/test_reply.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/test_doctor.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/test_explain.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/test_gamify.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/test_hook.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/test_learn.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/commands/test_overview.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/__init__.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_backend.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_capabilities.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_config.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_github.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_hook_io.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_journal.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_paths.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_render.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_resolve_backend.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/core/test_skill_loader.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/empty/.gitkeep +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/malformed/.claude/hooks.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/malformed/.claude/settings.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/malformed/.claude/skills/bad/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/malformed/.claude/skills/broken-yaml/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/typical/.claude/hooks.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/typical/.claude/settings.json +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/typical/.claude/skills/example/SKILL.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/fixtures/claude-code/typical/CLAUDE.md +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/test_cli_errors.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/test_cli_smoke.py +0 -0
- {agex_cli-0.22.0 → agex_cli-0.23.0}/tests/test_skill_md_consistency.py +0 -0
|
@@ -27,15 +27,20 @@ name: publish
|
|
|
27
27
|
# One-time setup on pypi.org / test.pypi.org and in the repo's Environments
|
|
28
28
|
# (`pypi`, `testpypi`) is documented in the original header below:
|
|
29
29
|
#
|
|
30
|
-
# - PyPI project `agex-cli`
|
|
31
|
-
#
|
|
30
|
+
# - For EACH PyPI project (`agex-cli`, `agent-devex`, `devex-cli`)
|
|
31
|
+
# → Publishing → Add a GitHub pending publisher
|
|
32
|
+
# Owner: agentculture Repo: devex
|
|
32
33
|
# Workflow: publish.yml Environment: pypi
|
|
33
34
|
#
|
|
34
|
-
# -
|
|
35
|
+
# - Same for EACH TestPyPI project, Environment: testpypi
|
|
35
36
|
#
|
|
36
37
|
# - GitHub repo → Settings → Environments → create `pypi` and `testpypi`
|
|
37
38
|
# (any required reviewers / wait timers live there)
|
|
38
39
|
#
|
|
40
|
+
# NOTE: the repo was renamed agentculture/agex-cli → agentculture/devex.
|
|
41
|
+
# The pre-existing `agex-cli` / `agent-devex` publishers must have their
|
|
42
|
+
# Repo updated to `devex` too, or those legs start failing OIDC.
|
|
43
|
+
#
|
|
39
44
|
# The PR job rewrites `version = "X.Y.Z"` to `"X.Y.Z.devN"` where N is
|
|
40
45
|
# the workflow run number. PEP 440's dev segment is a single integer
|
|
41
46
|
# (internal dots aren't allowed), so run_attempt is NOT encoded in the
|
|
@@ -67,10 +72,11 @@ jobs:
|
|
|
67
72
|
# pull_request -- the PR path has its own build inside `publish-pr-testpypi`
|
|
68
73
|
# because it needs to rewrite the version before building.
|
|
69
74
|
#
|
|
70
|
-
# The matrix exists so we can publish the same code under
|
|
71
|
-
# distribution names: `agex-cli` (canonical)
|
|
72
|
-
# Each leg rewrites `[project].name` in pyproject.toml
|
|
73
|
-
# each wheel is uploaded under its own Trusted Publishing
|
|
75
|
+
# The matrix exists so we can publish the same code under three PyPI
|
|
76
|
+
# distribution names: `agex-cli` (canonical) plus the `agent-devex` and
|
|
77
|
+
# `devex-cli` aliases. Each leg rewrites `[project].name` in pyproject.toml
|
|
78
|
+
# before building so each wheel is uploaded under its own Trusted Publishing
|
|
79
|
+
# project.
|
|
74
80
|
# --------------------------------------------------------------------------
|
|
75
81
|
build:
|
|
76
82
|
if: github.event_name == 'push'
|
|
@@ -78,7 +84,7 @@ jobs:
|
|
|
78
84
|
strategy:
|
|
79
85
|
fail-fast: false
|
|
80
86
|
matrix:
|
|
81
|
-
dist_name: [agex-cli, agent-devex]
|
|
87
|
+
dist_name: [agex-cli, agent-devex, devex-cli]
|
|
82
88
|
permissions:
|
|
83
89
|
contents: read # actions/checkout
|
|
84
90
|
steps:
|
|
@@ -93,8 +99,8 @@ jobs:
|
|
|
93
99
|
|
|
94
100
|
# Rewrite `[project].name` to the matrix dist name. For `agex-cli`
|
|
95
101
|
# (the canonical dist) the regex still has to match so we re-emit
|
|
96
|
-
# the line; for `agent-devex` it produces an alias dist
|
|
97
|
-
# identical contents. The post-rewrite re-parse is a fail-closed
|
|
102
|
+
# the line; for `agent-devex` / `devex-cli` it produces an alias dist
|
|
103
|
+
# with identical contents. The post-rewrite re-parse is a fail-closed
|
|
98
104
|
# check: if a future formatting change breaks the regex match (or
|
|
99
105
|
# `[project].name` ends up wrong for any reason), the job aborts
|
|
100
106
|
# before uploading mis-named artifacts.
|
|
@@ -150,7 +156,7 @@ jobs:
|
|
|
150
156
|
strategy:
|
|
151
157
|
fail-fast: false
|
|
152
158
|
matrix:
|
|
153
|
-
dist_name: [agex-cli, agent-devex]
|
|
159
|
+
dist_name: [agex-cli, agent-devex, devex-cli]
|
|
154
160
|
environment: testpypi
|
|
155
161
|
permissions:
|
|
156
162
|
id-token: write # OIDC -- Trusted Publishing
|
|
@@ -273,7 +279,7 @@ jobs:
|
|
|
273
279
|
strategy:
|
|
274
280
|
fail-fast: false
|
|
275
281
|
matrix:
|
|
276
|
-
dist_name: [agex-cli, agent-devex]
|
|
282
|
+
dist_name: [agex-cli, agent-devex, devex-cli]
|
|
277
283
|
environment: testpypi
|
|
278
284
|
permissions:
|
|
279
285
|
id-token: write # OIDC; no API token needed
|
|
@@ -372,7 +378,7 @@ jobs:
|
|
|
372
378
|
strategy:
|
|
373
379
|
fail-fast: false
|
|
374
380
|
matrix:
|
|
375
|
-
dist_name: [agex-cli, agent-devex]
|
|
381
|
+
dist_name: [agex-cli, agent-devex, devex-cli]
|
|
376
382
|
environment: pypi
|
|
377
383
|
permissions:
|
|
378
384
|
id-token: write # OIDC; no API token needed
|
|
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.23.0] - 2026-05-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `devex` console command — second entry point alongside `agex`; both invoke the same CLI and emitted output (Next-step footers, briefing/template headers, error prefixes) reflects whichever name was typed, via the new single-source-of-truth `core.prog.prog_name()` injected into the render context.
|
|
15
|
+
- Third PyPI distribution name `devex-cli` — the same wheel now publishes under `agex-cli` (canonical), `agent-devex`, and `devex-cli`; version resolution and the publish matrices cover all three.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Repo renamed `agentculture/agex-cli` → `agentculture/devex`; updated in-code issue/repo URLs, README, CLAUDE.md, and the publish workflow OIDC setup notes.
|
|
20
|
+
- SonarCloud project key → `agentculture_devex` (display name `devex`; organization unchanged).
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- "Output follows invocation" now also covers **plain-string** stdout/stderr in command scripts (`explain`/`learn`/`hook`/`doctor`/`gamify`/`pr delta`/`pr reply` error prefixes, status lines, and command examples), not just Jinja-rendered templates — added `core.prog.error_prefix()` and routed those paths through `prog_name()` (agex-cli#61 Qodo review).
|
|
25
|
+
- `prog_name()` now strips entry-point wrapper suffixes (`.exe`, `.py`, `-script`) before matching, so a real `devex` invocation via the Windows console script `devex.exe` no longer falls back to `agex` (agex-cli#61 Qodo review).
|
|
26
|
+
|
|
10
27
|
## [0.22.0] - 2026-05-25
|
|
11
28
|
|
|
12
29
|
### Added
|
|
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
4
4
|
|
|
5
5
|
## Project
|
|
6
6
|
|
|
7
|
-
`agex` — non-agentic Python CLI that emits deterministic per-backend markdown briefings for autonomous agents. PyPI distribution
|
|
7
|
+
`agex` — non-agentic Python CLI that emits deterministic per-backend markdown briefings for autonomous agents. Published on PyPI under three distribution names: `agex-cli` (canonical), `agent-devex`, and `devex-cli` — the same wheel each time. CLI entry points: `agex` and `devex` (both invoke the same tool; emitted output reflects whichever name was typed). GitHub repo: `agentculture/devex`. Python module (unchanged): `agent_experience`.
|
|
8
8
|
|
|
9
9
|
**Source-of-truth documents:**
|
|
10
10
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agex-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.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/agex/
|
|
6
|
-
Project-URL: Repository, https://github.com/agentculture/
|
|
7
|
-
Project-URL: Issues, https://github.com/agentculture/
|
|
6
|
+
Project-URL: Repository, https://github.com/agentculture/devex
|
|
7
|
+
Project-URL: Issues, https://github.com/agentculture/devex/issues
|
|
8
8
|
Author: Ori Nachum
|
|
9
9
|
License: MIT
|
|
10
10
|
License-File: LICENSE
|
|
@@ -26,14 +26,14 @@ Description-Content-Type: text/markdown
|
|
|
26
26
|
|
|
27
27
|
# agex
|
|
28
28
|
|
|
29
|
-
Agent-operated developer-experience CLI. Non-agentic, deterministic, markdown-first.
|
|
29
|
+
Agent-operated developer-experience CLI. Non-agentic, deterministic, markdown-first. The same wheel is published on PyPI under three distribution names — `agex-cli` (canonical), `agent-devex`, and `devex-cli` — and installs two equivalent commands, `agex` and `devex` (emitted output reflects whichever name you invoke).
|
|
30
30
|
|
|
31
31
|
## Install
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
uv tool install agex-cli
|
|
34
|
+
uv tool install agex-cli # or: devex-cli
|
|
35
35
|
# or
|
|
36
|
-
pipx install agex-cli
|
|
36
|
+
pipx install agex-cli # or: pipx install devex-cli
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Quick start
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# agex
|
|
2
|
+
|
|
3
|
+
Agent-operated developer-experience CLI. Non-agentic, deterministic, markdown-first. The same wheel is published on PyPI under three distribution names — `agex-cli` (canonical), `agent-devex`, and `devex-cli` — and installs two equivalent commands, `agex` and `devex` (emitted output reflects whichever name you invoke).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv tool install agex-cli # or: devex-cli
|
|
9
|
+
# or
|
|
10
|
+
pipx install agex-cli # or: pipx install devex-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
agex explain agex
|
|
17
|
+
agex overview --agent claude-code
|
|
18
|
+
agex learn --agent claude-code
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Docs
|
|
22
|
+
|
|
23
|
+
[culture.dev/agex](https://culture.dev/agex/).
|
|
24
|
+
|
|
25
|
+
Spec: `docs/superpowers/specs/2026-04-18-agex-design.md`.
|
|
26
|
+
|
|
27
|
+
## License
|
|
28
|
+
|
|
29
|
+
MIT.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agex-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.23.0"
|
|
4
4
|
description = "Agent-operated developer-experience CLI — deterministic per-backend markdown briefings for autonomous agents."
|
|
5
5
|
authors = [{name = "Ori Nachum"}]
|
|
6
6
|
license = {text = "MIT"}
|
|
@@ -27,11 +27,12 @@ dev = [
|
|
|
27
27
|
|
|
28
28
|
[project.scripts]
|
|
29
29
|
agex = "agent_experience.cli:_main_entrypoint"
|
|
30
|
+
devex = "agent_experience.cli:_main_entrypoint"
|
|
30
31
|
|
|
31
32
|
[project.urls]
|
|
32
33
|
Homepage = "https://culture.dev/agex/"
|
|
33
|
-
Repository = "https://github.com/agentculture/
|
|
34
|
-
Issues = "https://github.com/agentculture/
|
|
34
|
+
Repository = "https://github.com/agentculture/devex"
|
|
35
|
+
Issues = "https://github.com/agentculture/devex/issues"
|
|
35
36
|
|
|
36
37
|
[build-system]
|
|
37
38
|
requires = ["hatchling"]
|
|
@@ -2,13 +2,14 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def _resolve_version() -> str:
|
|
5
|
-
# `agex-cli` is the canonical PyPI distribution name; `agent-devex`
|
|
6
|
-
# alias
|
|
7
|
-
# Whichever one is installed, surface its metadata
|
|
8
|
-
# fallback for unbuilt source checkouts (no installed
|
|
9
|
-
# read the version directly from the repo's pyproject.toml
|
|
10
|
-
# stays single-sourced from pyproject.toml in every
|
|
11
|
-
|
|
5
|
+
# `agex-cli` is the canonical PyPI distribution name; `agent-devex` and
|
|
6
|
+
# `devex-cli` are alias distributions that ship the identical wheel under
|
|
7
|
+
# different names. Whichever one is installed, surface its metadata
|
|
8
|
+
# version. As a final fallback for unbuilt source checkouts (no installed
|
|
9
|
+
# dist metadata), read the version directly from the repo's pyproject.toml
|
|
10
|
+
# so the version stays single-sourced from pyproject.toml in every
|
|
11
|
+
# reachable code path.
|
|
12
|
+
for dist in ("agex-cli", "agent-devex", "devex-cli"):
|
|
12
13
|
try:
|
|
13
14
|
return version(dist)
|
|
14
15
|
except PackageNotFoundError:
|
|
@@ -28,11 +28,16 @@ from agent_experience.commands.pr.scripts import open_ as pr_open_script
|
|
|
28
28
|
from agent_experience.commands.pr.scripts import read as pr_read_script
|
|
29
29
|
from agent_experience.commands.pr.scripts import reply as pr_reply_script
|
|
30
30
|
from agent_experience.core.backend import parse_backend
|
|
31
|
+
from agent_experience.core.prog import prog_name
|
|
31
32
|
|
|
32
|
-
_GH_RERUN_HINT = "agex: rerun once network is reachable (gh failed)"
|
|
33
33
|
_AGENT_HELP = "Backend: claude-code, codex, copilot, or acp."
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def _gh_rerun_hint() -> str:
|
|
37
|
+
"""``<prog>: rerun once network is reachable`` — phrased with the invoked name."""
|
|
38
|
+
return f"{prog_name()}: rerun once network is reachable (gh failed)"
|
|
39
|
+
|
|
40
|
+
|
|
36
41
|
class _AgexArgumentParser(argparse.ArgumentParser):
|
|
37
42
|
"""ArgumentParser used everywhere via ``parser_class=``.
|
|
38
43
|
|
|
@@ -71,7 +76,7 @@ def _parse_backend_or_report(agent: Optional[str]):
|
|
|
71
76
|
try:
|
|
72
77
|
return parse_backend(agent), None
|
|
73
78
|
except ValueError as exc:
|
|
74
|
-
print(f"
|
|
79
|
+
print(f"{prog_name()}: error: {exc}", file=sys.stderr)
|
|
75
80
|
return None, 2
|
|
76
81
|
|
|
77
82
|
|
|
@@ -156,7 +161,7 @@ def _cmd_pr_lint(args: argparse.Namespace) -> int:
|
|
|
156
161
|
agent=args.agent, project_dir=Path.cwd(), exit_on_violation=args.exit_on_violation
|
|
157
162
|
)
|
|
158
163
|
except ValueError as exc:
|
|
159
|
-
print(f"
|
|
164
|
+
print(f"{prog_name()}: {exc}", file=sys.stderr)
|
|
160
165
|
return 2
|
|
161
166
|
_emit(stdout, stderr)
|
|
162
167
|
return exit_code
|
|
@@ -173,11 +178,12 @@ def _cmd_pr_open(args: argparse.Namespace) -> int:
|
|
|
173
178
|
delayed_read=args.delayed_read,
|
|
174
179
|
)
|
|
175
180
|
except ValueError as exc:
|
|
176
|
-
print(f"
|
|
181
|
+
print(f"{prog_name()}: {exc}", file=sys.stderr)
|
|
177
182
|
return 2
|
|
178
183
|
except RuntimeError as exc:
|
|
184
|
+
prog = prog_name()
|
|
179
185
|
print(str(exc), file=sys.stderr)
|
|
180
|
-
print("
|
|
186
|
+
print(f"{prog}: rerun '{prog} pr open ...' once network is reachable", file=sys.stderr)
|
|
181
187
|
return 1
|
|
182
188
|
_emit(stdout, stderr)
|
|
183
189
|
return exit_code
|
|
@@ -189,11 +195,11 @@ def _cmd_pr_reply(args: argparse.Namespace) -> int:
|
|
|
189
195
|
agent=args.agent, project_dir=Path.cwd(), pr=args.pr
|
|
190
196
|
)
|
|
191
197
|
except ValueError as exc:
|
|
192
|
-
print(f"
|
|
198
|
+
print(f"{prog_name()}: {exc}", file=sys.stderr)
|
|
193
199
|
return 2
|
|
194
200
|
except RuntimeError as exc:
|
|
195
201
|
print(str(exc), file=sys.stderr)
|
|
196
|
-
print(
|
|
202
|
+
print(_gh_rerun_hint(), file=sys.stderr)
|
|
197
203
|
return 1
|
|
198
204
|
_emit(stdout, stderr, stderr_newline=False)
|
|
199
205
|
return exit_code
|
|
@@ -205,11 +211,11 @@ def _cmd_pr_read(args: argparse.Namespace) -> int:
|
|
|
205
211
|
agent=args.agent, project_dir=Path.cwd(), pr=args.pr, wait=args.wait
|
|
206
212
|
)
|
|
207
213
|
except ValueError as exc:
|
|
208
|
-
print(f"
|
|
214
|
+
print(f"{prog_name()}: {exc}", file=sys.stderr)
|
|
209
215
|
return 2
|
|
210
216
|
except RuntimeError as exc:
|
|
211
217
|
print(str(exc), file=sys.stderr)
|
|
212
|
-
print(
|
|
218
|
+
print(_gh_rerun_hint(), file=sys.stderr)
|
|
213
219
|
return 1
|
|
214
220
|
_emit(stdout, stderr)
|
|
215
221
|
return exit_code
|
|
@@ -221,11 +227,11 @@ def _cmd_pr_await(args: argparse.Namespace) -> int:
|
|
|
221
227
|
agent=args.agent, project_dir=Path.cwd(), pr=args.pr, max_wait=args.max_wait
|
|
222
228
|
)
|
|
223
229
|
except ValueError as exc:
|
|
224
|
-
print(f"
|
|
230
|
+
print(f"{prog_name()}: {exc}", file=sys.stderr)
|
|
225
231
|
return 2
|
|
226
232
|
except RuntimeError as exc:
|
|
227
233
|
print(str(exc), file=sys.stderr)
|
|
228
|
-
print(
|
|
234
|
+
print(_gh_rerun_hint(), file=sys.stderr)
|
|
229
235
|
return 1
|
|
230
236
|
_emit(stdout, stderr)
|
|
231
237
|
return exit_code
|
|
@@ -235,11 +241,11 @@ def _cmd_pr_delta(args: argparse.Namespace) -> int:
|
|
|
235
241
|
try:
|
|
236
242
|
stdout, exit_code, stderr = pr_delta_script.run(agent=args.agent, project_dir=Path.cwd())
|
|
237
243
|
except ValueError as exc:
|
|
238
|
-
print(f"
|
|
244
|
+
print(f"{prog_name()}: {exc}", file=sys.stderr)
|
|
239
245
|
return 2
|
|
240
246
|
except RuntimeError as exc:
|
|
241
247
|
print(str(exc), file=sys.stderr)
|
|
242
|
-
print(
|
|
248
|
+
print(_gh_rerun_hint(), file=sys.stderr)
|
|
243
249
|
return 1
|
|
244
250
|
_emit(stdout, stderr, stderr_newline=False)
|
|
245
251
|
return exit_code
|
|
@@ -270,7 +276,7 @@ def _group_help(parser: argparse.ArgumentParser):
|
|
|
270
276
|
|
|
271
277
|
def _build_parser() -> argparse.ArgumentParser:
|
|
272
278
|
parser = _AgexArgumentParser(
|
|
273
|
-
prog=
|
|
279
|
+
prog=prog_name(),
|
|
274
280
|
description="Agent-operated developer-experience CLI.",
|
|
275
281
|
)
|
|
276
282
|
parser.add_argument("--version", action="version", version=__version__)
|
|
@@ -441,7 +447,9 @@ def _main_entrypoint() -> None:
|
|
|
441
447
|
"""
|
|
442
448
|
argv = sys.argv[1:]
|
|
443
449
|
if argv and not argv[0].startswith("-") and argv[0] not in _KNOWN_COMMANDS:
|
|
444
|
-
print(f"
|
|
450
|
+
print(f"{prog_name()}: error: unknown command '{argv[0]}'", file=sys.stderr)
|
|
451
|
+
# `agex` here is the explain-topic identifier (topics/agex.md), not the
|
|
452
|
+
# invoked command name — the canonical "what is this tool" page.
|
|
445
453
|
stdout, _, _ = explain_script.run("agex")
|
|
446
454
|
sys.stdout.write(stdout)
|
|
447
455
|
sys.exit(2)
|
|
@@ -24,6 +24,7 @@ from agent_experience.core.paths import (
|
|
|
24
24
|
config_path,
|
|
25
25
|
data_dir,
|
|
26
26
|
)
|
|
27
|
+
from agent_experience.core.prog import error_prefix
|
|
27
28
|
from agent_experience.core.render import render_string
|
|
28
29
|
from agent_experience.core.skill_loader import load_skill
|
|
29
30
|
|
|
@@ -74,8 +75,8 @@ def _check_version() -> CheckResult:
|
|
|
74
75
|
_NAME_AGEX_VERSION,
|
|
75
76
|
"fail",
|
|
76
77
|
"Could not resolve `agent_experience.__version__`. Reinstall with "
|
|
77
|
-
"`uv pip install -e .[dev]`, `pipx install agex-cli`,
|
|
78
|
-
"`pipx install agent-devex`.",
|
|
78
|
+
"`uv pip install -e .[dev]`, `pipx install agex-cli`, "
|
|
79
|
+
"`pipx install agent-devex`, or `pipx install devex-cli`.",
|
|
79
80
|
)
|
|
80
81
|
return CheckResult(_NAME_AGEX_VERSION, "ok", __version__)
|
|
81
82
|
|
|
@@ -341,24 +342,24 @@ def run(role: str | None = None) -> tuple[str, int, str]:
|
|
|
341
342
|
Read-only. Never initializes ``.agex/``.
|
|
342
343
|
"""
|
|
343
344
|
if role is not None and _ROLE_RE.match(role) is None:
|
|
344
|
-
return ("", 2, f"
|
|
345
|
+
return ("", 2, error_prefix(f"invalid role slug '{role}'"))
|
|
345
346
|
|
|
346
347
|
role_section: str | None = None
|
|
347
348
|
if role is not None:
|
|
348
349
|
trav = _resolve_role(role)
|
|
349
350
|
if trav is None:
|
|
350
|
-
return ("", 2, f"
|
|
351
|
+
return ("", 2, error_prefix(f"unknown role '{role}'"))
|
|
351
352
|
try:
|
|
352
353
|
role_text = trav.read_text(encoding="utf-8")
|
|
353
354
|
except (OSError, UnicodeDecodeError) as exc:
|
|
354
|
-
return ("", 1, f"
|
|
355
|
+
return ("", 1, error_prefix(f"could not read role asset for '{role}': {exc}"))
|
|
355
356
|
# Role assets are Jinja templates per the addendum spec; v0.1 passes
|
|
356
357
|
# an empty context but rendering still resolves any `{% raw %}` /
|
|
357
358
|
# `{{ }}` markup the role file may use, rather than dumping it raw.
|
|
358
359
|
try:
|
|
359
360
|
role_section = render_string(role_text, {})
|
|
360
361
|
except Exception as exc:
|
|
361
|
-
return ("", 1, f"
|
|
362
|
+
return ("", 1, error_prefix(f"failed to render role '{role}': {exc}"))
|
|
362
363
|
|
|
363
364
|
categories = _build_categories()
|
|
364
365
|
summary = _summarize(categories)
|
|
@@ -369,8 +370,10 @@ def run(role: str | None = None) -> tuple[str, int, str]:
|
|
|
369
370
|
return (
|
|
370
371
|
"",
|
|
371
372
|
1,
|
|
372
|
-
|
|
373
|
-
|
|
373
|
+
error_prefix(
|
|
374
|
+
f"could not read `doctor/assets/report.md.j2`: {exc}. "
|
|
375
|
+
"Reinstall the package."
|
|
376
|
+
),
|
|
374
377
|
)
|
|
375
378
|
out = render_string(
|
|
376
379
|
template_text,
|
|
@@ -386,6 +389,6 @@ def run(role: str | None = None) -> tuple[str, int, str]:
|
|
|
386
389
|
)
|
|
387
390
|
|
|
388
391
|
if summary["fail"] > 0:
|
|
389
|
-
stderr = f"
|
|
392
|
+
stderr = error_prefix(f"{summary['fail']} health check(s) failed")
|
|
390
393
|
return (out, 1, stderr)
|
|
391
394
|
return (out, 0, "")
|
{agex_cli-0.22.0 → agex_cli-0.23.0}/src/agent_experience/commands/explain/scripts/explain.py
RENAMED
|
@@ -2,6 +2,7 @@ import re
|
|
|
2
2
|
from importlib.resources import files
|
|
3
3
|
from importlib.resources.abc import Traversable
|
|
4
4
|
|
|
5
|
+
from agent_experience.core.prog import error_prefix
|
|
5
6
|
from agent_experience.core.skill_loader import Skill, load_skill
|
|
6
7
|
|
|
7
8
|
_TOPIC_RE = re.compile(r"^[a-z][a-z0-9-]*$")
|
|
@@ -54,7 +55,7 @@ def run(topic: str) -> tuple[str, int, str]:
|
|
|
54
55
|
if resolved is None:
|
|
55
56
|
agex_page = _commands_root().joinpath("explain", "assets", "topics", "agex.md")
|
|
56
57
|
body = agex_page.read_text(encoding="utf-8") if agex_page.is_file() else ""
|
|
57
|
-
return (body, 2, f"
|
|
58
|
+
return (body, 2, error_prefix(f"unknown topic '{topic}'"))
|
|
58
59
|
|
|
59
60
|
kind, trav = resolved
|
|
60
61
|
if kind == "concept":
|
|
@@ -8,6 +8,7 @@ from agent_experience.core.backend import Backend
|
|
|
8
8
|
from agent_experience.core.config import load as load_config
|
|
9
9
|
from agent_experience.core.config import save as save_config
|
|
10
10
|
from agent_experience.core.paths import ensure_init
|
|
11
|
+
from agent_experience.core.prog import error_prefix, prog_name
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def _fragments_file() -> Traversable:
|
|
@@ -110,7 +111,7 @@ def install(backend: Backend) -> tuple[str, int, str]:
|
|
|
110
111
|
try:
|
|
111
112
|
hooks = _load_hooks_file(hooks_file)
|
|
112
113
|
except ValueError as e:
|
|
113
|
-
return ("", 2,
|
|
114
|
+
return ("", 2, error_prefix(str(e)))
|
|
114
115
|
|
|
115
116
|
written_ids, added_count = _merge_fragments(hooks, fragments)
|
|
116
117
|
if added_count:
|
|
@@ -142,7 +143,8 @@ def install(backend: Backend) -> tuple[str, int, str]:
|
|
|
142
143
|
status_line,
|
|
143
144
|
"- Fragment IDs: " + ", ".join(f"`{i}`" for i in written_ids),
|
|
144
145
|
"",
|
|
145
|
-
f"Next: run `
|
|
146
|
+
f"Next: run `{prog_name()} learn gamify --agent {backend.value}`"
|
|
147
|
+
" to set up the levelup skill.",
|
|
146
148
|
"",
|
|
147
149
|
]
|
|
148
150
|
return ("\n".join(lines), 0, "")
|
|
@@ -176,7 +178,7 @@ def uninstall(backend: Backend) -> tuple[str, int, str]:
|
|
|
176
178
|
try:
|
|
177
179
|
hooks = _load_hooks_file(hooks_file)
|
|
178
180
|
except ValueError as e:
|
|
179
|
-
return ("", 2,
|
|
181
|
+
return ("", 2, error_prefix(str(e)))
|
|
180
182
|
|
|
181
183
|
removed_count = _remove_ids_from_hooks(hooks, ids_to_remove)
|
|
182
184
|
if removed_count:
|
|
@@ -196,6 +198,6 @@ def _unsupported_notice(backend: Backend) -> str:
|
|
|
196
198
|
return (
|
|
197
199
|
f"## `gamify` is not supported on {backend.value}\n\n"
|
|
198
200
|
f"Hooks are required to track usage events, and {backend.value} does not expose "
|
|
199
|
-
f"a hook interface
|
|
200
|
-
"Want this supported? Open an issue: <https://github.com/agentculture/
|
|
201
|
+
f"a hook interface {prog_name()} can write to.\n\n"
|
|
202
|
+
"Want this supported? Open an issue: <https://github.com/agentculture/devex/issues>\n"
|
|
201
203
|
)
|
|
@@ -2,6 +2,7 @@ from datetime import datetime, timezone
|
|
|
2
2
|
|
|
3
3
|
from agent_experience.core.hook_io import append_event
|
|
4
4
|
from agent_experience.core.paths import ensure_init
|
|
5
|
+
from agent_experience.core.prog import error_prefix
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def run(event: str, args: list[str]) -> tuple[str, int, str]:
|
|
@@ -20,5 +21,5 @@ def run(event: str, args: list[str]) -> tuple[str, int, str]:
|
|
|
20
21
|
except ValueError as e:
|
|
21
22
|
# append_event → _stream_path rejects names that don't match the
|
|
22
23
|
# `^[a-z][a-z0-9-]*$` slug whitelist (path-traversal guard).
|
|
23
|
-
return ("", 2,
|
|
24
|
+
return ("", 2, error_prefix(str(e)))
|
|
24
25
|
return ("", 0, "")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lessons — {{ backend }}
|
|
2
2
|
|
|
3
|
-
Run `
|
|
3
|
+
Run `{{ prog }} learn <topic> --agent {{ backend }}` to learn one.
|
|
4
4
|
|
|
5
5
|
{% for topic in topics -%}
|
|
6
6
|
- **`{{ topic.name }}`** — {{ topic.description }}{% if topic.unsupported %} _(unsupported on {{ backend }}: {{ topic.unsupported }})_{% endif %}
|
|
@@ -3,6 +3,7 @@ from importlib.resources import as_file, files
|
|
|
3
3
|
from importlib.resources.abc import Traversable
|
|
4
4
|
|
|
5
5
|
from agent_experience.core.backend import Backend
|
|
6
|
+
from agent_experience.core.prog import error_prefix
|
|
6
7
|
from agent_experience.core.render import render_string
|
|
7
8
|
from agent_experience.core.skill_loader import Skill, load_skill
|
|
8
9
|
|
|
@@ -54,13 +55,13 @@ def run_topic(topic: str, backend: Backend) -> tuple[str, int, str]:
|
|
|
54
55
|
"""Return (stdout, exit_code, stderr) for a specific lesson topic."""
|
|
55
56
|
if not _TOPIC_RE.match(topic):
|
|
56
57
|
menu_out, _, _ = run_menu(backend)
|
|
57
|
-
return (menu_out, 2, f"
|
|
58
|
+
return (menu_out, 2, error_prefix(f"unknown topic '{topic}'"))
|
|
58
59
|
|
|
59
60
|
topic_dir = _learn_assets().joinpath("topics", topic)
|
|
60
61
|
skill_md = topic_dir.joinpath(_SKILL_FILENAME)
|
|
61
62
|
if not skill_md.is_file():
|
|
62
63
|
menu_out, _, _ = run_menu(backend)
|
|
63
|
-
return (menu_out, 2, f"
|
|
64
|
+
return (menu_out, 2, error_prefix(f"unknown topic '{topic}'"))
|
|
64
65
|
|
|
65
66
|
skill = _load_skill_from_traversable(skill_md)
|
|
66
67
|
template_path = topic_dir.joinpath("assets", "skill-template", backend.value, _SKILL_FILENAME)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
hints:
|
|
2
|
+
lint_clean: "Commit, push, then `{{ prog }} pr open --title \"...\"`."
|
|
3
|
+
lint_clean_with_alignment: "Run `{{ prog }} pr delta` (this PR touches alignment files), then commit, push, and `{{ prog }} pr open --title \"...\"`."
|
|
4
|
+
lint_violations: "Fix the {{ violation_count }} violation(s) above and rerun `{{ prog }} pr lint`."
|
|
5
|
+
open_recommend_read: "`{{ prog }} pr read {{ pr }} --wait 180` (recommended) or `{{ prog }} pr read {{ pr }}` in ~3 min."
|
|
6
|
+
open_already_exists: "PR already open as #{{ pr }} — `{{ prog }} pr read {{ pr }} --wait 180` to fetch the briefing."
|
|
7
|
+
read_unresolved_after_commits: "Push fixes, then `{{ prog }} pr read {{ pr }} --wait 180`."
|
|
8
|
+
read_unresolved_no_commits: "Triage and prepare `replies.jsonl`, then `{{ prog }} pr reply {{ pr }} < replies.jsonl`."
|
|
9
|
+
read_ci_red: "Fix CI before requesting re-review (see failing checks above)."
|
|
10
|
+
read_clean: "Wait for human merge."
|
|
11
|
+
read_wait_timeout: "Still waiting on: {{ reviewers }}. Rerun `{{ prog }} pr read {{ pr }} --wait 180` to continue."
|
|
12
|
+
reply_with_failures: "Resubmit the failed lines (see table above) to `{{ prog }} pr reply {{ pr }}`."
|
|
13
|
+
reply_clean: "Push fixes (if any), then `{{ prog }} pr read {{ pr }} --wait 180`."
|
|
14
|
+
delta_done: "Triage each sibling — open follow-up PRs where alignment drifted; mention them in your reply."
|
|
15
|
+
await_clean: "PR #{{ pr }} is ready — wait for human merge."
|
|
16
|
+
await_gate_error: "SonarCloud quality gate is ERROR — fix the new issues above, push, then `{{ prog }} pr await {{ pr }}` again."
|
|
17
|
+
await_gate_unknown: "SonarCloud quality gate is UNKNOWN — analysis is pending or the project isn't analyzed yet; wait and re-run `{{ prog }} pr await {{ pr }}`."
|
|
18
|
+
await_unresolved_threads: "Triage and prepare `replies.jsonl`, then `{{ prog }} pr reply {{ pr }} < replies.jsonl`."
|
|
19
|
+
await_ci_red: "Fix CI before requesting re-review (see failing checks above)."
|
|
20
|
+
await_wait_timeout: "Still waiting on: {{ reviewers }}. Rerun `{{ prog }} pr await {{ pr }}` to keep waiting."
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
hints:
|
|
2
|
+
lint_clean: "Commit, push, then `{{ prog }} pr open --title \"...\"`."
|
|
3
|
+
lint_clean_with_alignment: "Run `{{ prog }} pr delta` (this PR touches alignment files), then commit, push, and `{{ prog }} pr open --title \"...\"`."
|
|
4
|
+
lint_violations: "Fix the {{ violation_count }} violation(s) above and rerun `{{ prog }} pr lint`."
|
|
5
|
+
open_recommend_read: "`{{ prog }} pr read {{ pr }} --wait 180` (recommended) or `{{ prog }} pr read {{ pr }}` in ~3 min."
|
|
6
|
+
open_already_exists: "PR already open as #{{ pr }} — `{{ prog }} pr read {{ pr }} --wait 180` to fetch the briefing."
|
|
7
|
+
read_unresolved_after_commits: "Push fixes, then `{{ prog }} pr read {{ pr }} --wait 180`."
|
|
8
|
+
read_unresolved_no_commits: "Triage and prepare `replies.jsonl`, then `{{ prog }} pr reply {{ pr }} < replies.jsonl`."
|
|
9
|
+
read_ci_red: "Fix CI before requesting re-review (see failing checks above)."
|
|
10
|
+
read_clean: "Wait for human merge."
|
|
11
|
+
read_wait_timeout: "Still waiting on: {{ reviewers }}. Rerun `{{ prog }} pr read {{ pr }} --wait 180` to continue."
|
|
12
|
+
reply_with_failures: "Resubmit the failed lines (see table above) to `{{ prog }} pr reply {{ pr }}`."
|
|
13
|
+
reply_clean: "Push fixes (if any), then `{{ prog }} pr read {{ pr }} --wait 180`."
|
|
14
|
+
delta_done: "Triage each sibling — open follow-up PRs where alignment drifted; mention them in your reply."
|
|
15
|
+
await_clean: "PR #{{ pr }} is ready — wait for human merge."
|
|
16
|
+
await_gate_error: "SonarCloud quality gate is ERROR — fix the new issues above, push, then `{{ prog }} pr await {{ pr }}` again."
|
|
17
|
+
await_gate_unknown: "SonarCloud quality gate is UNKNOWN — analysis is pending or the project isn't analyzed yet; wait and re-run `{{ prog }} pr await {{ pr }}`."
|
|
18
|
+
await_unresolved_threads: "Triage and prepare `replies.jsonl`, then `{{ prog }} pr reply {{ pr }} < replies.jsonl`."
|
|
19
|
+
await_ci_red: "Fix CI before requesting re-review (see failing checks above)."
|
|
20
|
+
await_wait_timeout: "Still waiting on: {{ reviewers }}. Rerun `{{ prog }} pr await {{ pr }}` to keep waiting."
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
hints:
|
|
2
|
+
lint_clean: "Commit, push, then `{{ prog }} pr open --title \"...\"`."
|
|
3
|
+
lint_clean_with_alignment: "Run `{{ prog }} pr delta` (this PR touches alignment files), then commit, push, and `{{ prog }} pr open --title \"...\"`."
|
|
4
|
+
lint_violations: "Fix the {{ violation_count }} violation(s) above and rerun `{{ prog }} pr lint`."
|
|
5
|
+
open_recommend_read: "`{{ prog }} pr read {{ pr }} --wait 180` (recommended) or `{{ prog }} pr read {{ pr }}` in ~3 min."
|
|
6
|
+
open_already_exists: "PR already open as #{{ pr }} — `{{ prog }} pr read {{ pr }} --wait 180` to fetch the briefing."
|
|
7
|
+
read_unresolved_after_commits: "Push fixes, then `{{ prog }} pr read {{ pr }} --wait 180`."
|
|
8
|
+
read_unresolved_no_commits: "Triage and prepare `replies.jsonl`, then `{{ prog }} pr reply {{ pr }} < replies.jsonl`."
|
|
9
|
+
read_ci_red: "Fix CI before requesting re-review (see failing checks above)."
|
|
10
|
+
read_clean: "Wait for human merge."
|
|
11
|
+
read_wait_timeout: "Still waiting on: {{ reviewers }}. Rerun `{{ prog }} pr read {{ pr }} --wait 180` to continue."
|
|
12
|
+
reply_with_failures: "Resubmit the failed lines (see table above) to `{{ prog }} pr reply {{ pr }}`."
|
|
13
|
+
reply_clean: "Push fixes (if any), then `{{ prog }} pr read {{ pr }} --wait 180`."
|
|
14
|
+
delta_done: "Triage each sibling — open follow-up PRs where alignment drifted; mention them in your reply."
|
|
15
|
+
await_clean: "PR #{{ pr }} is ready — wait for human merge."
|
|
16
|
+
await_gate_error: "SonarCloud quality gate is ERROR — fix the new issues above, push, then `{{ prog }} pr await {{ pr }}` again."
|
|
17
|
+
await_gate_unknown: "SonarCloud quality gate is UNKNOWN — analysis is pending or the project isn't analyzed yet; wait and re-run `{{ prog }} pr await {{ pr }}`."
|
|
18
|
+
await_unresolved_threads: "Triage and prepare `replies.jsonl`, then `{{ prog }} pr reply {{ pr }} < replies.jsonl`."
|
|
19
|
+
await_ci_red: "Fix CI before requesting re-review (see failing checks above)."
|
|
20
|
+
await_wait_timeout: "Still waiting on: {{ reviewers }}. Rerun `{{ prog }} pr await {{ pr }}` to keep waiting."
|