devflow-cli 6.0.0__tar.gz → 6.1.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.
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/CHANGELOG.md +14 -0
- devflow_cli-6.1.0/FEEDBACK.md +176 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/PKG-INFO +1 -1
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/activity-contracts.md +13 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/cli-reference.md +9 -0
- devflow_cli-6.1.0/docs/releases/6.1.0.md +54 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/pyproject.toml +1 -1
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/__init__.py +1 -1
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/adapters/agents.py +200 -3
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/cli.py +2 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/adaptive.py +61 -0
- devflow_cli-6.1.0/src/devflow_cli/commands/usage.py +92 -0
- devflow_cli-6.1.0/src/devflow_cli/core/telemetry.py +168 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/conftest.py +10 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_adaptive.py +81 -1
- devflow_cli-6.1.0/tests/test_telemetry.py +278 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/uv.lock +1 -1
- devflow_cli-6.0.0/FEEDBACK.md +0 -224
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.ai/mcp/mcp.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.analyze.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.checklist.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.clarify.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.constitution.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.implement.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.specify.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.taskstoissues.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.githooks/post-checkout +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.githooks/post-merge +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.github/workflows/ci.yml +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.github/workflows/release.yml +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.gitignore +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/init-options.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/memory/constitution.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/check-prerequisites.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/common.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/create-new-feature.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/setup-plan.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/update-agent-context.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/contracts/cli-init.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/contracts/cli-regen.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/contracts/cli-status-staleness.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/contracts/cli-commands.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/contracts/cli-upgrade.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/018-fix-final-robustness/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/checklists/requirements.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/contracts/orchestrator-contract.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/data-model.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/plan.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/quickstart.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/research.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/spec.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/tasks.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/agent-file-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/checklist-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/constitution-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/plan-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template-brownfield.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template-greenfield.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template-microservices.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/tasks-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/CLAUDE.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/CONTRIBUTING.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/LICENSE +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/README.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.context.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.extension.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.init.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.regen.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.status.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/adr/0001-v4-workflow-compatibility.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/adr/0002-v5-rupture-and-provenance.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/commands-reference.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/cursor-guide.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/guides/brownfield.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/guides/greenfield.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/guides/microservices.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/index.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/pipeline-reference.generated.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/pipeline.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.0.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.1.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.3.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.4.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.5.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.6.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/5.0.0.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/6.0.0.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/spec-driven.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/v5-decisions.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/v6-decisions.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/EXTENSION-API-REFERENCE.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/catalog.community.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/catalog.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/template/example-command.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/template/example-extension.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/scripts/check_release.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/adapters/__init__.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/adapters/linear.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/__init__.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/assess.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/check.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/context.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/docs_sync.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/export_cmd.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/extension.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/feature.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/hooks_cmd.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/init_cmd.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/linear.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/stale.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/status.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/traceability.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/upgrade_cmd.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/verify.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/__init__.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/activity_contracts.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/adaptive_runner.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/adaptive_workflow.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/agent_failure.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/assessment.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/automatic_evidence.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/catalog.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/contract_schemas.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/docgen.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/git.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/hooks.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/installer.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/manifest.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/omissions.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/operational.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/redaction.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/remediation.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/scanner.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/staleness.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/traceability.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/validation_approvals.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/validators.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/verification.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/waivers.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/worklog.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/worktree_snapshot.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/activity-contract-v3.schema.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/activity-result-v1.schema.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/assessment-v3.schema.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/workflow-state-v4.schema.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/__init__.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/console.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/logging.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/paths.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/strings.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/agent-context-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/constitution-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/README-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/api-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/components-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/interfaces-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/services-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/data-model-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/devflow-hooks-template.yml +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/extension-manifest-template.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/plan-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/quickstart-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/research-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/spec-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/tasks-template.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/fixtures/agents/mock-agent.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/fixtures/commands/mock-command.md +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/fixtures/mock-catalog.json +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/run-tests.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test-helpers.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test-template-variants.sh +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_activity_contracts.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_adaptive_runner.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_adaptive_workflow.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_agent_adapters.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_agent_failure.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_assessment.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_automatic_evidence.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_bash_runner.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_catalog.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_assess.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_check.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_context.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_docs_sync.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_extension.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_feature.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_hooks.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_init.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_linear.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_stale.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_status.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_traceability.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_upgrade.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_verify.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_constants.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_context.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_contract_schemas.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_docgen.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_git.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_hooks.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_installer.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_integration.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_linear_adapter.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_linear_order.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_logging.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_manifest.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_omissions.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_paths.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_paths_project_root.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_release.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_remediation.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_scanner.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_staleness.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_traceability.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_validators.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_verification.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_version.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_waivers.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_wheel_adaptive_acceptance.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_wheel_install.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_worklog.py +0 -0
- {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_worktree_snapshot.py +0 -0
|
@@ -5,6 +5,20 @@ Tous les changements notables de ce projet sont documentés dans ce fichier.
|
|
|
5
5
|
Le format est basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/),
|
|
6
6
|
et ce projet adhère au [Semantic Versioning](https://semver.org/lang/fr/).
|
|
7
7
|
|
|
8
|
+
## [6.1.0] - 2026-09-24
|
|
9
|
+
|
|
10
|
+
Mesure de consommation des agents : voir [notes de version](docs/releases/6.1.0.md).
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Télémétrie locale de consommation : chaque tentative `adaptive run` ajoute
|
|
15
|
+
une ligne à `~/.devflow/telemetry.jsonl` (tokens, tours, modèle, coût
|
|
16
|
+
équivalent API Claude, deltas de quota Codex), sans prompt ni contenu.
|
|
17
|
+
Désactivable avec `DEVFLOW_TELEMETRY=0`.
|
|
18
|
+
- `devflow usage` résume ces tentatives par activité, profil, agent, modèle ou
|
|
19
|
+
projet, avec `--since`, `--project` et `--json`.
|
|
20
|
+
- `agent-execution.json` porte le `runId` de la tentative correspondante.
|
|
21
|
+
|
|
8
22
|
## [6.0.0] - 2026-09-24
|
|
9
23
|
|
|
10
24
|
Retours d'usage k-review traités : voir [v6-decisions.md](docs/v6-decisions.md).
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Retours d'usage devflow
|
|
2
|
+
|
|
3
|
+
Observés en conditions réelles. Chaque entrée : ce qui s'est passé, pourquoi ça coûte, une piste.
|
|
4
|
+
Les décisions t'appartiennent. Classement par gravité.
|
|
5
|
+
|
|
6
|
+
Retours précédents traités en 5.0.0 : voir `docs/v5-decisions.md`. Ceux de la série suivante en
|
|
7
|
+
6.0.0 : voir `docs/v6-decisions.md`.
|
|
8
|
+
|
|
9
|
+
**Contexte des retours ci-dessous.** Projet k-review, trois parcours conduits les 23 et 24 septembre
|
|
10
|
+
2026 : KKS-368 `deep`, KKS-369 `deep`, KKS-370 `standard`. Point de vue : celui du superviseur
|
|
11
|
+
(Claude), qui enchaîne les activités, rédige lui-même les artefacts, délègue l'implémentation à des
|
|
12
|
+
agents et répare les rejets.
|
|
13
|
+
|
|
14
|
+
**Réserve à lire avant tout.** Ces parcours ont été conduits avec la **CLI v5.0.0** : la 6.0.0 a été
|
|
15
|
+
publiée alors que le dernier se terminait. Chaque entrée ci-dessous a donc été **revérifiée contre le
|
|
16
|
+
code de la 6.0.0** avant d'être écrite, et celles que la 6.0.0 corrige déjà ne figurent pas dans les
|
|
17
|
+
sections de gravité — elles sont rassemblées en fin de document, à titre de confirmation.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Majeur
|
|
22
|
+
|
|
23
|
+
### M1 — Le profil `standard` n'a aucune activité de revue
|
|
24
|
+
|
|
25
|
+
**Ce qui s'est passé.** KKS-370 a été évalué `standard` : `assess → prepare → preflight-evidence →
|
|
26
|
+
implement → verify → done`. Il n'y a **pas d'activité `review`**, et la preuve `implementation-review`
|
|
27
|
+
n'est pas requise — contrairement au profil `deep`, où les deux existent.
|
|
28
|
+
|
|
29
|
+
Or ce lot modifiait `app.html`, le gabarit du **shell partagé par les quatre écrans** de
|
|
30
|
+
l'application, en changeant l'ordre du DOM. Une régression y aurait été visible partout à la fois. Le
|
|
31
|
+
projet impose par ailleurs deux revues d'agent avant chaque commit ; elles ont été jouées, mais
|
|
32
|
+
**hors du parcours**, sans point d'ancrage ni trace dans l'état du workflow.
|
|
33
|
+
|
|
34
|
+
**Pourquoi ça coûte.** La rigueur de revue est indexée sur le profil, donc sur l'ampleur estimée du
|
|
35
|
+
changement, et non sur le **risque de ce qui est touché**. Un lot `standard` qui modifie un composant
|
|
36
|
+
partagé est moins contrôlé qu'un lot `deep` qui ajoute un fichier isolé. Le commit a lieu dans les
|
|
37
|
+
deux cas, et rien dans les artefacts ne dit qu'une revue a eu lieu : `done` se complète sans elle.
|
|
38
|
+
|
|
39
|
+
**Piste.** Permettre au `risk-assessment` de **recommander l'ajout** d'une activité `review` à un
|
|
40
|
+
profil qui ne la porte pas, symétriquement à l'omission introduite en 6.0.0 pour `critical`
|
|
41
|
+
(`adaptive omit`). Ou rendre `implementation-review` exigible dès qu'un fichier du périmètre est
|
|
42
|
+
partagé par plusieurs modules. À défaut, un `adaptive review` accepté en `standard` pour consigner
|
|
43
|
+
une revue qui a eu lieu, même sans activité dédiée.
|
|
44
|
+
|
|
45
|
+
### M2 — Le plafond de dix commandes n'est pas dans la politique injectée
|
|
46
|
+
|
|
47
|
+
**Ce qui s'est passé.** `activity_contracts.py:788` refuse tout `validationPlan` de plus de dix
|
|
48
|
+
commandes : `validationPlan doit contenir entre 1 et 10 commandes`. La politique exposée aux agents
|
|
49
|
+
par `validation_policy_guidance()` (`verification.py:70`) énumère les exécutables autorisés, les
|
|
50
|
+
tâches Maven et Gradle, les opérateurs interdits, l'approbation des exécutables hors liste et la
|
|
51
|
+
consigne sur `git ls-files` — **mais pas ce plafond**.
|
|
52
|
+
|
|
53
|
+
Sur KKS-368, le plan comptait onze validations, toutes légitimes et distinctes. Le refus est arrivé à
|
|
54
|
+
`verify`, après rédaction du plan **et** du document qui le décrit.
|
|
55
|
+
|
|
56
|
+
**Pourquoi ça coûte.** Ce n'est pas seulement une commande à retirer : il faut en **fusionner** deux
|
|
57
|
+
qui portaient des garanties différentes, puis amender le document de plan pour qu'aucun écart ne
|
|
58
|
+
subsiste entre ce qui est écrit et ce qui s'exécute. Le retour de M1 de la série précédente — « la
|
|
59
|
+
politique n'est connue qu'après coup » — a été traité, mais cette contrainte-là y a échappé, alors
|
|
60
|
+
qu'elle est la plus facile à énoncer.
|
|
61
|
+
|
|
62
|
+
**Piste.** Ajouter une ligne à `validation_policy_guidance()` : « le validationPlan contient entre 1
|
|
63
|
+
et 10 commandes ; regrouper plutôt qu'énumérer ». Une seule phrase ferme le sujet.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 2. Mineur
|
|
68
|
+
|
|
69
|
+
### m1 — `adaptive review` complète l'activité, et son nom ne le dit pas
|
|
70
|
+
|
|
71
|
+
**Ce qui s'est passé.** Sur KKS-369, `adaptive review` rend : « Revue humaine de … validée pour
|
|
72
|
+
'review'. **Prochaine : done** ». L'enchaînement naturel, `adaptive complete KKS-369 review`, échoue
|
|
73
|
+
alors avec « activité courante attendue : done ».
|
|
74
|
+
|
|
75
|
+
**Pourquoi ça coûte.** Un aller-retour et un doute : on ne sait pas si la revue a été prise en compte
|
|
76
|
+
ou si l'on a sauté une étape. Le verbe `review` suggère d'enregistrer une revue, pas de terminer
|
|
77
|
+
l'activité.
|
|
78
|
+
|
|
79
|
+
**Piste.** Le message de succès pourrait dire que l'activité est complétée, pas seulement quelle est
|
|
80
|
+
la suivante : « Revue enregistrée, activité 'review' complétée. Prochaine : done ».
|
|
81
|
+
|
|
82
|
+
### m2 — Le format `evidence` des résultats est accepté sans être compris
|
|
83
|
+
|
|
84
|
+
**Ce qui s'est passé.** Les `*-result.json` acceptent un tableau `evidence`. Un objet de la forme
|
|
85
|
+
`{id, kind, summary, path}` passe la validation du résultat **sans erreur**, mais ne compte comme
|
|
86
|
+
aucune preuve : `complete review` a refusé avec « preuves manquantes : implementation-review » alors
|
|
87
|
+
qu'une entrée portant `"id": "implementation-review"` figurait dans le fichier. Le format reconnu est
|
|
88
|
+
`{id, outcome, report}`, et l'`id` doit être le **nom du type de preuve attendu**.
|
|
89
|
+
|
|
90
|
+
**Pourquoi ça coûte.** Le message de refus décrit l'état des preuves, pas ce qui a été lu dans le
|
|
91
|
+
fichier. On corrige le format à l'aveugle, on relance, on échoue encore — jusqu'à aller lire un
|
|
92
|
+
`workflow-state.json` d'un lot précédent pour en déduire la forme attendue.
|
|
93
|
+
|
|
94
|
+
**Piste.** Signaler les entrées `evidence` non reconnues au moment de la complétion, avec la forme
|
|
95
|
+
attendue : « entrée ignorée : clés {kind, summary, path} ; attendu {id, outcome, report} ».
|
|
96
|
+
|
|
97
|
+
### m3 — Le porteur du `validationPlan` change avec le profil, sans être annoncé
|
|
98
|
+
|
|
99
|
+
**Ce qui s'est passé.** En `standard`, le `validationPlan` va dans `prepare-result.json`. En `deep`,
|
|
100
|
+
il n'y a pas d'activité `prepare` : c'est `plan-result.json` qui doit le porter. Son absence ne se
|
|
101
|
+
manifeste qu'à `verify`, par `invalid-preparation-result` — un code dont le nom désigne une activité
|
|
102
|
+
qui n'existe pas dans ce profil.
|
|
103
|
+
|
|
104
|
+
**Pourquoi ça coûte.** Le message n'indique pas quel fichier remplir, et son intitulé oriente vers la
|
|
105
|
+
mauvaise piste. Sur KKS-368, la cause n'a été trouvée qu'en comparant avec le dossier d'un lot
|
|
106
|
+
antérieur conduit sous un autre profil.
|
|
107
|
+
|
|
108
|
+
**Piste.** Nommer le fichier attendu dans le refus : « validationPlan absent de plan-result.json
|
|
109
|
+
(profil deep : pas d'activité prepare) ». Le contrat d'activité pourrait aussi le rappeler, puisqu'il
|
|
110
|
+
demande déjà « un validationPlan exécutable et portable est fourni » sans dire où.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 3. Hors outil, mais rencontré en le pilotant
|
|
115
|
+
|
|
116
|
+
### h1 — Rien n'oblige une conclusion d'absence à se prouver
|
|
117
|
+
|
|
118
|
+
**Ce qui s'est passé.** KKS-370 était un lot d'audit : son premier temps produisait un constat, le
|
|
119
|
+
second corrigeait. Le constat a conclu deux fois à une **absence** — « aucune gestion de mise à jour
|
|
120
|
+
du service worker n'existe », « aucun renvoi au principe de couleur dans le code ». Les deux étaient
|
|
121
|
+
faux. Un service complet existait depuis quatre lots ; il y avait trois renvois. Les deux erreurs
|
|
122
|
+
venaient de recherches dont la sortie avait été tronquée.
|
|
123
|
+
|
|
124
|
+
Ces faux constats sont entrés dans `audit.md`, puis dans le périmètre, puis dans les instructions
|
|
125
|
+
données à un agent d'implémentation — qui a refusé d'écrire le code et a corrigé le superviseur. Un
|
|
126
|
+
arbitrage a été demandé à l'utilisateur pour un travail sans objet.
|
|
127
|
+
|
|
128
|
+
**Pourquoi ça coûte.** L'activité `preflight-evidence` demande des « faits observés » et vérifie que
|
|
129
|
+
les sections existent, mais ne distingue pas un fait **positif** — mesuré, reproductible — d'une
|
|
130
|
+
**absence constatée**, qui n'est un fait que si la recherche était exhaustive. Une absence mal établie
|
|
131
|
+
se propage plus loin qu'une mesure fausse, parce qu'elle justifie de **construire** quelque chose.
|
|
132
|
+
|
|
133
|
+
**Piste.** Dans le contrat de `preflight-evidence`, demander que toute affirmation d'absence cite la
|
|
134
|
+
commande qui l'établit, et que cette commande figure dans la section de reproductibilité. C'est une
|
|
135
|
+
consigne, pas un contrôle — mais elle aurait suffi ici : écrire la commande aurait exposé le `head`
|
|
136
|
+
qui la tronquait.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 4. Ce que la 6.0.0 corrige, vérifié
|
|
141
|
+
|
|
142
|
+
Ces points figuraient dans mes retours précédents ou ont été rencontrés en v5.0.0 pendant ces
|
|
143
|
+
parcours. Ils sont **résolus**, et je les note pour fermer la boucle plutôt que pour demander quoi que
|
|
144
|
+
ce soit.
|
|
145
|
+
|
|
146
|
+
- **m4, preuves `manual` refusées.** `adaptive evidence --help` annonce désormais « Enregistre une
|
|
147
|
+
preuve manuelle informative, **sans ouvrir les gates** ». En v5.0.0, la commande acceptait
|
|
148
|
+
l'enregistrement puis la complétion échouait avec « preuves automatiques valides requises », sans
|
|
149
|
+
jamais nommer `adaptive review`. L'aide actuelle aurait évité l'aller-retour.
|
|
150
|
+
- **M6, messages sans cible.** Le refus `regression-check-failed (PREP-conflit-plus-non-tranche)`
|
|
151
|
+
nomme l'identifiant exact de la validation fautive, en première ligne. J'ai trouvé la cause
|
|
152
|
+
immédiatement — c'était une validation que j'avais moi-même mal conçue.
|
|
153
|
+
- **M1, politique connue après coup.** Les sections requises sont nommées dans le refus : « sections
|
|
154
|
+
de pré-vol manquantes : faits observés, reproductibilité, limites ». Trois mots suffisent à
|
|
155
|
+
corriger.
|
|
156
|
+
- **Le refus de réduire un profil recommandé** reste strict, et c'est bien. Déclarer
|
|
157
|
+
`--contract-change` sur une route ajoutée fait recommander `deep` ; `--profile standard` est
|
|
158
|
+
refusé. Le contourner en retirant le drapeau marcherait, et mentirait sur la nature du changement.
|
|
159
|
+
Le garde-fou tient exactement là où il doit tenir.
|
|
160
|
+
- **`devflow traceability`** joué avant de compléter `tasks` rend la couverture des exigences par les
|
|
161
|
+
tâches en une seconde. Deux écarts rattrapés sur KKS-369 à ce moment-là plutôt qu'à la revue.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Priorités suggérées
|
|
166
|
+
|
|
167
|
+
1. **M2** — une phrase dans `validation_policy_guidance()`. Coût nul, évite un rejet tardif et une
|
|
168
|
+
réécriture de document.
|
|
169
|
+
2. **m3** — nommer le fichier attendu dans le refus `invalid-preparation-result`. Coût nul, supprime
|
|
170
|
+
la recherche à l'aveugle.
|
|
171
|
+
3. **M1** — la revue absente du profil `standard` est le seul point qui touche la qualité du résultat
|
|
172
|
+
plutôt que le confort du pilote. C'est aussi le plus lourd à trancher : il engage la définition des
|
|
173
|
+
profils.
|
|
174
|
+
4. **m2** et **m1** — messages, à traiter quand l'occasion se présente.
|
|
175
|
+
5. **h1** — une consigne de contrat, si l'idée te paraît juste. Elle sort du périmètre habituel de
|
|
176
|
+
l'outil, et je la propose sans insister.
|
|
@@ -291,6 +291,19 @@ distingue une réponse finale absente, un fichier vide, un tour échoué, un JSO
|
|
|
291
291
|
invalide et un payload refusé par le schéma; aucun de ces cas ne fait progresser
|
|
292
292
|
le workflow.
|
|
293
293
|
|
|
294
|
+
Chaque tentative agent est aussi consignée, avec le même `runId`, dans
|
|
295
|
+
`~/.devflow/telemetry.jsonl` : contrat, profil, activité, résultat Devflow,
|
|
296
|
+
durée et compteurs de consommation. Claude fournit ses tokens, son nombre de
|
|
297
|
+
tours, ses modèles et son coût équivalent API dans l'enveloppe JSON. Le flux
|
|
298
|
+
Codex ne donne que les tokens ; le modèle, l'effort, le nombre de requêtes, le
|
|
299
|
+
contexte au premier tour et l'évolution des quotas sont lus au mieux dans le
|
|
300
|
+
journal de session `~/.codex/sessions` (ou `$CODEX_HOME/sessions`), dont le
|
|
301
|
+
format est interne à Codex. Le delta de quota est mesuré entre le premier et le
|
|
302
|
+
dernier relevé de la session et vaut `null` si la fenêtre a été réinitialisée.
|
|
303
|
+
Une mesure illisible laisse `usage` à `null`; une écriture impossible affiche un
|
|
304
|
+
avertissement; aucune ne bloque l'activité. Aucun prompt, aucune réponse et aucun
|
|
305
|
+
contenu de fichier n'y figure.
|
|
306
|
+
|
|
294
307
|
Les activités documentaires Deep écrivent exclusivement `spec.md`, `plan.md`
|
|
295
308
|
ou `tasks.md`, puis réutilisent les validateurs historiques et le contrôle de
|
|
296
309
|
traçabilité exigences-tâches. Leurs résultats sont conservés dans
|
|
@@ -155,6 +155,7 @@ devflow verify ISSUE_ID [--json] [--allow-command OUTIL]
|
|
|
155
155
|
devflow stale ISSUE_ID
|
|
156
156
|
devflow context ISSUE_ID
|
|
157
157
|
devflow linear decision ACTIVITY CURRENT_STATUS
|
|
158
|
+
devflow usage [--since 7d|DATE] [--by activity|profile|agent|model|project] [--project TEXTE] [--json]
|
|
158
159
|
```
|
|
159
160
|
|
|
160
161
|
Avec un workflow adaptatif, `devflow verify` utilise les mêmes preuves et
|
|
@@ -163,6 +164,14 @@ réservée aux plans sans workflow adaptatif ; utiliser `approve-command` pour
|
|
|
163
164
|
une feature adaptative. Les tableaux Markdown historiques acceptent une
|
|
164
165
|
colonne « Répertoire » relative au dépôt.
|
|
165
166
|
|
|
167
|
+
Chaque tentative `adaptive run` confiée à un agent ajoute une ligne à
|
|
168
|
+
`~/.devflow/telemetry.jsonl`, commun à tous les projets puisque les quotas sont
|
|
169
|
+
partagés par le compte. `devflow usage` en résume les tentatives, les
|
|
170
|
+
activités avancées, les tokens, le coût équivalent API déclaré par Claude, le
|
|
171
|
+
nombre de tours et les points de quota Codex ; `--json` ajoute le cache écrit et
|
|
172
|
+
le contexte médian au premier tour. `DEVFLOW_TELEMETRY=0` désactive la collecte
|
|
173
|
+
et `DEVFLOW_HOME` déplace le répertoire.
|
|
174
|
+
|
|
166
175
|
## Formats antérieurs
|
|
167
176
|
|
|
168
177
|
Devflow 5 refuse tout workflow créé par une version antérieure et ne fournit
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Devflow 6.1.0 — Mesurer la consommation des agents
|
|
2
|
+
|
|
3
|
+
Cette version ne change aucune transition du workflow. Elle enregistre ce que
|
|
4
|
+
coûte chaque tentative confiée à un agent, afin de décider plus tard du modèle,
|
|
5
|
+
de l'effort ou du profil à partir de données réelles plutôt que de journaux
|
|
6
|
+
externes difficiles à corréler.
|
|
7
|
+
|
|
8
|
+
## Télémétrie locale
|
|
9
|
+
|
|
10
|
+
- Chaque tentative `adaptive run` confiée à un agent, avancée ou refusée, ajoute
|
|
11
|
+
une ligne à `~/.devflow/telemetry.jsonl`. Le fichier est commun à tous les
|
|
12
|
+
projets, car les quotas des agents sont partagés par le compte.
|
|
13
|
+
- Une ligne porte le contrat, le profil, l'activité, le projet, le résultat
|
|
14
|
+
Devflow, la durée et les compteurs de consommation. Aucun prompt, aucune
|
|
15
|
+
réponse et aucun contenu de fichier n'y figure.
|
|
16
|
+
- **Claude** : tokens d'entrée, de cache et de sortie, nombre de tours, modèles,
|
|
17
|
+
sous-agents et coût équivalent API, lus dans l'enveloppe JSON.
|
|
18
|
+
- **Codex** : tokens lus dans le flux `--json` ; modèle, effort, nombre de
|
|
19
|
+
requêtes, contexte au premier tour et évolution des fenêtres de quota lus au
|
|
20
|
+
mieux dans le journal de session `~/.codex/sessions` (ou
|
|
21
|
+
`$CODEX_HOME/sessions`).
|
|
22
|
+
- `agent-execution.json` porte le `runId` de la ligne correspondante.
|
|
23
|
+
- La collecte est active par défaut ; `DEVFLOW_TELEMETRY=0` la désactive et
|
|
24
|
+
`DEVFLOW_HOME` déplace le répertoire.
|
|
25
|
+
- Une mesure illisible laisse `usage` à `null` ; une écriture impossible affiche
|
|
26
|
+
un avertissement. Aucune des deux ne bloque l'activité.
|
|
27
|
+
|
|
28
|
+
## Lecture
|
|
29
|
+
|
|
30
|
+
`devflow usage [--since 7d|DATE] [--by activity|profile|agent|model|project]
|
|
31
|
+
[--project TEXTE] [--json]` résume les tentatives, les activités avancées, les
|
|
32
|
+
tokens, le coût équivalent API Claude, le nombre moyen de tours et les points
|
|
33
|
+
de quota Codex. `--json` ajoute le cache écrit et le contexte médian au premier
|
|
34
|
+
tour.
|
|
35
|
+
|
|
36
|
+
## Limites connues
|
|
37
|
+
|
|
38
|
+
- Les tokens Claude et Codex ne sont pas comparables entre eux, ni entre
|
|
39
|
+
modèles de prix différents.
|
|
40
|
+
- Claude ne fournit ni l'effort, ni le contexte au premier tour, ni l'état de
|
|
41
|
+
ses quotas.
|
|
42
|
+
- Le journal de session Codex a un format interne à Codex : un changement de
|
|
43
|
+
format vide les champs qui en proviennent sans erreur. Le delta de quota est
|
|
44
|
+
mesuré entre le premier et le dernier relevé de la session ; la première
|
|
45
|
+
requête n'y est donc pas comptée, et il vaut `null` si la fenêtre a été
|
|
46
|
+
réinitialisée.
|
|
47
|
+
- Cursor n'est pas mesuré.
|
|
48
|
+
- La réconciliation (`adaptive reconcile`) n'appelle pas d'agent et n'est pas
|
|
49
|
+
enregistrée.
|
|
50
|
+
|
|
51
|
+
## Validation de la version
|
|
52
|
+
|
|
53
|
+
- Suite complète : 677 tests pytest et 14 tests shell.
|
|
54
|
+
- `devflow docs-sync --check` confirme la référence générée des profils.
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
import os
|
|
6
7
|
import subprocess
|
|
7
8
|
import re
|
|
8
9
|
import time
|
|
9
10
|
from abc import ABC, abstractmethod
|
|
10
|
-
from dataclasses import dataclass
|
|
11
|
+
from dataclasses import dataclass, replace
|
|
12
|
+
from datetime import datetime, timedelta
|
|
11
13
|
from pathlib import Path
|
|
12
14
|
from typing import Literal
|
|
13
15
|
|
|
@@ -25,6 +27,38 @@ _SAFE_DIAGNOSTIC_MESSAGES = {
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
|
|
30
|
+
@dataclass(frozen=True)
|
|
31
|
+
class QuotaWindow:
|
|
32
|
+
"""Evolution d'une fenetre de quota observee pendant une session agent."""
|
|
33
|
+
|
|
34
|
+
windowMinutes: int | None
|
|
35
|
+
usedPercentStart: float
|
|
36
|
+
usedPercentEnd: float
|
|
37
|
+
# None si la fenetre a ete reinitialisee entre les deux releves.
|
|
38
|
+
deltaPoints: float | None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class AgentUsage:
|
|
43
|
+
"""Compteurs de consommation declares par l'agent, sans aucun contenu.
|
|
44
|
+
|
|
45
|
+
inputTokens exclut toujours les tokens lus depuis le cache.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
inputTokens: int = 0
|
|
49
|
+
cacheReadTokens: int = 0
|
|
50
|
+
cacheWriteTokens: int = 0
|
|
51
|
+
outputTokens: int = 0
|
|
52
|
+
reasoningTokens: int = 0
|
|
53
|
+
models: tuple[str, ...] = ()
|
|
54
|
+
effort: str | None = None
|
|
55
|
+
turns: int | None = None
|
|
56
|
+
costUsd: float | None = None
|
|
57
|
+
subagents: int | None = None
|
|
58
|
+
firstContextTokens: int | None = None
|
|
59
|
+
quota: tuple[QuotaWindow, ...] = ()
|
|
60
|
+
|
|
61
|
+
|
|
28
62
|
@dataclass(frozen=True)
|
|
29
63
|
class AgentExecution:
|
|
30
64
|
returncode: int
|
|
@@ -36,6 +70,7 @@ class AgentExecution:
|
|
|
36
70
|
final_output_bytes: int = 0
|
|
37
71
|
final_output_diagnostic: str = "not-evaluated"
|
|
38
72
|
session_id: str | None = None
|
|
73
|
+
usage: AgentUsage | None = None
|
|
39
74
|
|
|
40
75
|
|
|
41
76
|
class StructuredOutputError(ValueError):
|
|
@@ -138,6 +173,9 @@ class AgentAdapter(ABC):
|
|
|
138
173
|
final_output_diagnostic="process-failed" if result.returncode else "validating",
|
|
139
174
|
session_id=self.session_id(result.stdout or "", result.stderr or ""),
|
|
140
175
|
)
|
|
176
|
+
execution = replace(
|
|
177
|
+
execution, usage=self.safe_usage(execution.stdout, execution.session_id)
|
|
178
|
+
)
|
|
141
179
|
if execution.returncode != 0:
|
|
142
180
|
return execution
|
|
143
181
|
try:
|
|
@@ -169,6 +207,7 @@ class AgentAdapter(ABC):
|
|
|
169
207
|
_output_size(output_file),
|
|
170
208
|
"validated",
|
|
171
209
|
execution.session_id,
|
|
210
|
+
execution.usage,
|
|
172
211
|
)
|
|
173
212
|
|
|
174
213
|
status = _output_status(output_file)
|
|
@@ -189,16 +228,21 @@ class AgentAdapter(ABC):
|
|
|
189
228
|
final_output_bytes=size,
|
|
190
229
|
final_output_diagnostic=diagnostic,
|
|
191
230
|
session_id=execution.session_id,
|
|
231
|
+
usage=execution.usage,
|
|
192
232
|
)
|
|
193
233
|
except subprocess.TimeoutExpired as exc:
|
|
234
|
+
stdout, stderr = _text(exc.stdout), _text(exc.stderr)
|
|
235
|
+
session_id = self.session_id(stdout, stderr)
|
|
194
236
|
return AgentExecution(
|
|
195
237
|
124,
|
|
196
|
-
|
|
197
|
-
|
|
238
|
+
stdout,
|
|
239
|
+
stderr,
|
|
198
240
|
timed_out=True,
|
|
199
241
|
duration_seconds=time.monotonic() - started,
|
|
200
242
|
final_output_status=_output_status(output_file),
|
|
201
243
|
final_output_bytes=_output_size(output_file),
|
|
244
|
+
session_id=session_id,
|
|
245
|
+
usage=self.safe_usage(stdout, session_id),
|
|
202
246
|
)
|
|
203
247
|
except FileNotFoundError:
|
|
204
248
|
return AgentExecution(127, stderr=f"Executable '{self.executable}' introuvable", duration_seconds=time.monotonic() - started)
|
|
@@ -207,6 +251,17 @@ class AgentAdapter(ABC):
|
|
|
207
251
|
"""Extrait un identifiant opaque de session, sans conserver la sortie."""
|
|
208
252
|
return _session_id(stdout, stderr)
|
|
209
253
|
|
|
254
|
+
def usage(self, stdout: str, session_id: str | None) -> AgentUsage | None:
|
|
255
|
+
"""Extrait les compteurs de consommation ; None si l'agent n'en fournit pas."""
|
|
256
|
+
return None
|
|
257
|
+
|
|
258
|
+
def safe_usage(self, stdout: str, session_id: str | None) -> AgentUsage | None:
|
|
259
|
+
"""La mesure de consommation ne doit jamais faire echouer une activite."""
|
|
260
|
+
try:
|
|
261
|
+
return self.usage(stdout, session_id)
|
|
262
|
+
except Exception: # noqa: BLE001 - format externe non contractuel
|
|
263
|
+
return None
|
|
264
|
+
|
|
210
265
|
def recover_structured_payload(self, raw_output: str) -> object:
|
|
211
266
|
"""Extrait la reponse structuree d'une trace brute conservee apres un echec."""
|
|
212
267
|
return self._structured_payload(raw_output, None)
|
|
@@ -270,6 +325,33 @@ class ClaudeCodeAdapter(AgentAdapter):
|
|
|
270
325
|
return json.loads(_strip_json_fence(result))
|
|
271
326
|
raise ValueError("champ structured_output absent")
|
|
272
327
|
|
|
328
|
+
def usage(self, stdout: str, session_id: str | None) -> AgentUsage | None:
|
|
329
|
+
"""Lit l'enveloppe --output-format json : usage cumule de tous les tours."""
|
|
330
|
+
envelope = json.loads(stdout)
|
|
331
|
+
if not isinstance(envelope, dict) or not isinstance(envelope.get("usage"), dict):
|
|
332
|
+
return None
|
|
333
|
+
usage = envelope["usage"]
|
|
334
|
+
details = usage.get("output_tokens_details")
|
|
335
|
+
subagents = envelope.get("subagent_stats")
|
|
336
|
+
model_usage = envelope.get("modelUsage")
|
|
337
|
+
cost = envelope.get("total_cost_usd")
|
|
338
|
+
turns = envelope.get("num_turns")
|
|
339
|
+
return AgentUsage(
|
|
340
|
+
inputTokens=_int(usage.get("input_tokens")),
|
|
341
|
+
cacheReadTokens=_int(usage.get("cache_read_input_tokens")),
|
|
342
|
+
cacheWriteTokens=_int(usage.get("cache_creation_input_tokens")),
|
|
343
|
+
outputTokens=_int(usage.get("output_tokens")),
|
|
344
|
+
reasoningTokens=_int(details.get("thinking_tokens")) if isinstance(details, dict) else 0,
|
|
345
|
+
models=tuple(model_usage) if isinstance(model_usage, dict) else (),
|
|
346
|
+
turns=turns if isinstance(turns, int) else None,
|
|
347
|
+
costUsd=float(cost) if isinstance(cost, (int, float)) else None,
|
|
348
|
+
subagents=(
|
|
349
|
+
subagents.get("spawned")
|
|
350
|
+
if isinstance(subagents, dict) and isinstance(subagents.get("spawned"), int)
|
|
351
|
+
else None
|
|
352
|
+
),
|
|
353
|
+
)
|
|
354
|
+
|
|
273
355
|
|
|
274
356
|
class CodexAdapter(AgentAdapter):
|
|
275
357
|
name = "codex"
|
|
@@ -338,6 +420,32 @@ class CodexAdapter(AgentAdapter):
|
|
|
338
420
|
return json.loads(_strip_json_fence(final_message))
|
|
339
421
|
raise StructuredOutputError(diagnostic, message)
|
|
340
422
|
|
|
423
|
+
def usage(self, stdout: str, session_id: str | None) -> AgentUsage | None:
|
|
424
|
+
"""Combine le flux --json et, au mieux, le journal de session Codex.
|
|
425
|
+
|
|
426
|
+
Le flux ne donne que les tokens ; le modele, l'effort, le nombre de
|
|
427
|
+
requetes et les quotas ne figurent que dans le journal de session, dont
|
|
428
|
+
le format est interne a Codex.
|
|
429
|
+
"""
|
|
430
|
+
totals = [
|
|
431
|
+
event["usage"]
|
|
432
|
+
for event in json_line_events(stdout)
|
|
433
|
+
if event.get("type") == "turn.completed" and isinstance(event.get("usage"), dict)
|
|
434
|
+
]
|
|
435
|
+
session = _codex_session_facts(session_id)
|
|
436
|
+
if not totals and session is None:
|
|
437
|
+
return None
|
|
438
|
+
raw_input = sum(_int(item.get("input_tokens")) for item in totals)
|
|
439
|
+
cached = sum(_int(item.get("cached_input_tokens")) for item in totals)
|
|
440
|
+
usage = AgentUsage(
|
|
441
|
+
inputTokens=max(raw_input - cached, 0),
|
|
442
|
+
cacheReadTokens=cached,
|
|
443
|
+
cacheWriteTokens=sum(_int(item.get("cache_write_input_tokens")) for item in totals),
|
|
444
|
+
outputTokens=sum(_int(item.get("output_tokens")) for item in totals),
|
|
445
|
+
reasoningTokens=sum(_int(item.get("reasoning_output_tokens")) for item in totals),
|
|
446
|
+
)
|
|
447
|
+
return replace(usage, **session) if session else usage
|
|
448
|
+
|
|
341
449
|
|
|
342
450
|
class CursorAdapter(AgentAdapter):
|
|
343
451
|
name = "cursor"
|
|
@@ -492,3 +600,92 @@ def _validate_structured_payload(payload: object, schema_file: Path) -> None:
|
|
|
492
600
|
validator_type = validator_for(schema)
|
|
493
601
|
validator_type.check_schema(schema)
|
|
494
602
|
validator_type(schema).validate(payload)
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def _int(value: object) -> int:
|
|
606
|
+
return value if isinstance(value, int) and not isinstance(value, bool) else 0
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
def _codex_home() -> Path:
|
|
610
|
+
return Path(os.environ.get("CODEX_HOME") or Path.home() / ".codex")
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def _codex_session_file(session_id: str | None) -> Path | None:
|
|
614
|
+
"""Retrouve le journal d'une session Codex recente a partir de son identifiant."""
|
|
615
|
+
if not session_id or not re.fullmatch(r"[A-Za-z0-9-]{8,}", session_id):
|
|
616
|
+
return None
|
|
617
|
+
sessions = _codex_home() / "sessions"
|
|
618
|
+
today = datetime.now()
|
|
619
|
+
for offset in range(3):
|
|
620
|
+
day = today - timedelta(days=offset)
|
|
621
|
+
directory = sessions / f"{day:%Y}" / f"{day:%m}" / f"{day:%d}"
|
|
622
|
+
matches = sorted(directory.glob(f"rollout-*{session_id}.jsonl"))
|
|
623
|
+
if matches:
|
|
624
|
+
return matches[-1]
|
|
625
|
+
return None
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def _codex_session_facts(session_id: str | None) -> dict | None:
|
|
629
|
+
"""Extrait modele, effort, requetes et quotas du journal de session Codex."""
|
|
630
|
+
path = _codex_session_file(session_id)
|
|
631
|
+
if path is None:
|
|
632
|
+
return None
|
|
633
|
+
models: list[str] = []
|
|
634
|
+
effort: str | None = None
|
|
635
|
+
totals: set[int] = set()
|
|
636
|
+
first_context: int | None = None
|
|
637
|
+
limits: list[dict] = []
|
|
638
|
+
with path.open(encoding="utf-8", errors="replace") as handle:
|
|
639
|
+
for event in json_line_events(handle.read()):
|
|
640
|
+
payload = event.get("payload")
|
|
641
|
+
if not isinstance(payload, dict):
|
|
642
|
+
continue
|
|
643
|
+
if event.get("type") == "turn_context":
|
|
644
|
+
model = payload.get("model")
|
|
645
|
+
if isinstance(model, str) and model not in models:
|
|
646
|
+
models.append(model)
|
|
647
|
+
if isinstance(payload.get("effort"), str):
|
|
648
|
+
effort = payload["effort"]
|
|
649
|
+
elif event.get("type") == "event_msg" and payload.get("type") == "token_count":
|
|
650
|
+
info = payload.get("info")
|
|
651
|
+
if isinstance(info, dict) and isinstance(info.get("total_token_usage"), dict):
|
|
652
|
+
marker = _int(info["total_token_usage"].get("total_tokens"))
|
|
653
|
+
if marker not in totals:
|
|
654
|
+
totals.add(marker)
|
|
655
|
+
last = info.get("last_token_usage")
|
|
656
|
+
if first_context is None and isinstance(last, dict):
|
|
657
|
+
first_context = _int(last.get("input_tokens")) or None
|
|
658
|
+
if isinstance(payload.get("rate_limits"), dict):
|
|
659
|
+
limits.append(payload["rate_limits"])
|
|
660
|
+
return {
|
|
661
|
+
"models": tuple(models),
|
|
662
|
+
"effort": effort,
|
|
663
|
+
"turns": len(totals) or None,
|
|
664
|
+
"firstContextTokens": first_context,
|
|
665
|
+
"quota": _quota_windows(limits),
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
def _quota_windows(limits: list[dict]) -> tuple[QuotaWindow, ...]:
|
|
670
|
+
"""Compare le premier et le dernier releve de chaque fenetre de quota."""
|
|
671
|
+
windows: list[QuotaWindow] = []
|
|
672
|
+
if not limits:
|
|
673
|
+
return ()
|
|
674
|
+
for key in ("primary", "secondary"):
|
|
675
|
+
first, last = limits[0].get(key), limits[-1].get(key)
|
|
676
|
+
if not isinstance(first, dict) or not isinstance(last, dict):
|
|
677
|
+
continue
|
|
678
|
+
start, end = first.get("used_percent"), last.get("used_percent")
|
|
679
|
+
if not isinstance(start, (int, float)) or not isinstance(end, (int, float)):
|
|
680
|
+
continue
|
|
681
|
+
minutes = last.get("window_minutes")
|
|
682
|
+
same_window = first.get("resets_at") == last.get("resets_at")
|
|
683
|
+
windows.append(
|
|
684
|
+
QuotaWindow(
|
|
685
|
+
windowMinutes=minutes if isinstance(minutes, int) else None,
|
|
686
|
+
usedPercentStart=float(start),
|
|
687
|
+
usedPercentEnd=float(end),
|
|
688
|
+
deltaPoints=float(end) - float(start) if same_window else None,
|
|
689
|
+
)
|
|
690
|
+
)
|
|
691
|
+
return tuple(windows)
|
|
@@ -22,6 +22,7 @@ from devflow_cli.commands.docs_sync import docs_sync
|
|
|
22
22
|
from devflow_cli.commands.traceability import traceability
|
|
23
23
|
from devflow_cli.commands.verify import verify
|
|
24
24
|
from devflow_cli.commands.assess import assess
|
|
25
|
+
from devflow_cli.commands.usage import usage
|
|
25
26
|
|
|
26
27
|
app = typer.Typer(
|
|
27
28
|
name="devflow",
|
|
@@ -61,6 +62,7 @@ app.command(name="docs-sync")(docs_sync)
|
|
|
61
62
|
app.command()(traceability)
|
|
62
63
|
app.command()(verify)
|
|
63
64
|
app.command()(assess)
|
|
65
|
+
app.command()(usage)
|
|
64
66
|
|
|
65
67
|
|
|
66
68
|
if __name__ == "__main__":
|