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.
Files changed (365) hide show
  1. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/CHANGELOG.md +14 -0
  2. devflow_cli-6.1.0/FEEDBACK.md +176 -0
  3. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/PKG-INFO +1 -1
  4. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/activity-contracts.md +13 -0
  5. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/cli-reference.md +9 -0
  6. devflow_cli-6.1.0/docs/releases/6.1.0.md +54 -0
  7. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/pyproject.toml +1 -1
  8. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/__init__.py +1 -1
  9. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/adapters/agents.py +200 -3
  10. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/cli.py +2 -0
  11. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/adaptive.py +61 -0
  12. devflow_cli-6.1.0/src/devflow_cli/commands/usage.py +92 -0
  13. devflow_cli-6.1.0/src/devflow_cli/core/telemetry.py +168 -0
  14. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/conftest.py +10 -0
  15. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_adaptive.py +81 -1
  16. devflow_cli-6.1.0/tests/test_telemetry.py +278 -0
  17. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/uv.lock +1 -1
  18. devflow_cli-6.0.0/FEEDBACK.md +0 -224
  19. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.ai/mcp/mcp.json +0 -0
  20. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.analyze.md +0 -0
  21. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.checklist.md +0 -0
  22. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.clarify.md +0 -0
  23. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.constitution.md +0 -0
  24. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.implement.md +0 -0
  25. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.plan.md +0 -0
  26. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.specify.md +0 -0
  27. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.tasks.md +0 -0
  28. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.claude/commands/speckit.taskstoissues.md +0 -0
  29. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.githooks/post-checkout +0 -0
  30. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.githooks/post-merge +0 -0
  31. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.github/workflows/ci.yml +0 -0
  32. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.github/workflows/release.yml +0 -0
  33. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.gitignore +0 -0
  34. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/init-options.json +0 -0
  35. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/memory/constitution.md +0 -0
  36. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/check-prerequisites.sh +0 -0
  37. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/common.sh +0 -0
  38. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/create-new-feature.sh +0 -0
  39. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/setup-plan.sh +0 -0
  40. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/scripts/bash/update-agent-context.sh +0 -0
  41. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/checklists/requirements.md +0 -0
  42. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/contracts/cli-init.md +0 -0
  43. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/data-model.md +0 -0
  44. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/plan.md +0 -0
  45. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/research.md +0 -0
  46. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/spec.md +0 -0
  47. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/001-cli-init-options/tasks.md +0 -0
  48. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/checklists/requirements.md +0 -0
  49. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/contracts/cli-regen.md +0 -0
  50. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/contracts/cli-status-staleness.md +0 -0
  51. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/data-model.md +0 -0
  52. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/plan.md +0 -0
  53. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/research.md +0 -0
  54. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/spec.md +0 -0
  55. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/002-cascade-regen/tasks.md +0 -0
  56. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/checklists/requirements.md +0 -0
  57. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/data-model.md +0 -0
  58. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/plan.md +0 -0
  59. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/quickstart.md +0 -0
  60. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/research.md +0 -0
  61. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/spec.md +0 -0
  62. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/003-usecase-guides/tasks.md +0 -0
  63. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/checklists/requirements.md +0 -0
  64. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/contracts/cli-commands.md +0 -0
  65. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/data-model.md +0 -0
  66. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/plan.md +0 -0
  67. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/quickstart.md +0 -0
  68. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/research.md +0 -0
  69. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/spec.md +0 -0
  70. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/004-specify-central-directory/tasks.md +0 -0
  71. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/checklists/requirements.md +0 -0
  72. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/plan.md +0 -0
  73. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/quickstart.md +0 -0
  74. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/research.md +0 -0
  75. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/spec.md +0 -0
  76. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/005-implement-subphases/tasks.md +0 -0
  77. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/checklists/requirements.md +0 -0
  78. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/contracts/cli-upgrade.md +0 -0
  79. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/data-model.md +0 -0
  80. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/plan.md +0 -0
  81. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/quickstart.md +0 -0
  82. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/research.md +0 -0
  83. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/spec.md +0 -0
  84. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/006-template-upgrade/tasks.md +0 -0
  85. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/checklists/requirements.md +0 -0
  86. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/data-model.md +0 -0
  87. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/plan.md +0 -0
  88. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/quickstart.md +0 -0
  89. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/research.md +0 -0
  90. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/spec.md +0 -0
  91. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/007-project-documentation/tasks.md +0 -0
  92. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/checklists/requirements.md +0 -0
  93. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/plan.md +0 -0
  94. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/quickstart.md +0 -0
  95. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/research.md +0 -0
  96. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/spec.md +0 -0
  97. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/008-hardening-bugs/tasks.md +0 -0
  98. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/checklists/requirements.md +0 -0
  99. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/plan.md +0 -0
  100. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/quickstart.md +0 -0
  101. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/research.md +0 -0
  102. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/spec.md +0 -0
  103. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/009-ci-pypi/tasks.md +0 -0
  104. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/checklists/requirements.md +0 -0
  105. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/plan.md +0 -0
  106. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/quickstart.md +0 -0
  107. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/research.md +0 -0
  108. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/spec.md +0 -0
  109. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/010-flexible-pipeline/tasks.md +0 -0
  110. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/checklists/requirements.md +0 -0
  111. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/plan.md +0 -0
  112. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/quickstart.md +0 -0
  113. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/research.md +0 -0
  114. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/spec.md +0 -0
  115. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/011-cursor-support/tasks.md +0 -0
  116. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/checklists/requirements.md +0 -0
  117. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/plan.md +0 -0
  118. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/research.md +0 -0
  119. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/spec.md +0 -0
  120. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/012-fix-critical-bugs/tasks.md +0 -0
  121. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/checklists/requirements.md +0 -0
  122. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/plan.md +0 -0
  123. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/quickstart.md +0 -0
  124. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/spec.md +0 -0
  125. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/013-align-truth-sources/tasks.md +0 -0
  126. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/checklists/requirements.md +0 -0
  127. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/plan.md +0 -0
  128. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/quickstart.md +0 -0
  129. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/spec.md +0 -0
  130. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/014-enforce-state-machine/tasks.md +0 -0
  131. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/checklists/requirements.md +0 -0
  132. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/plan.md +0 -0
  133. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/research.md +0 -0
  134. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/spec.md +0 -0
  135. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/015-fix-review-contradiction/tasks.md +0 -0
  136. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/checklists/requirements.md +0 -0
  137. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/plan.md +0 -0
  138. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/research.md +0 -0
  139. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/spec.md +0 -0
  140. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/016-harden-state-machine/tasks.md +0 -0
  141. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/checklists/requirements.md +0 -0
  142. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/plan.md +0 -0
  143. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/research.md +0 -0
  144. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/spec.md +0 -0
  145. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/017-fix-robustness-issues/tasks.md +0 -0
  146. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/018-fix-final-robustness/spec.md +0 -0
  147. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/checklists/requirements.md +0 -0
  148. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/data-model.md +0 -0
  149. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/plan.md +0 -0
  150. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/research.md +0 -0
  151. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/spec.md +0 -0
  152. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/019-quality-hardening/tasks.md +0 -0
  153. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/checklists/requirements.md +0 -0
  154. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/data-model.md +0 -0
  155. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/plan.md +0 -0
  156. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/quickstart.md +0 -0
  157. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/research.md +0 -0
  158. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/spec.md +0 -0
  159. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/020-migrate-speckit/tasks.md +0 -0
  160. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/checklists/requirements.md +0 -0
  161. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/plan.md +0 -0
  162. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/research.md +0 -0
  163. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/spec.md +0 -0
  164. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/021-review-iterations/tasks.md +0 -0
  165. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/checklists/requirements.md +0 -0
  166. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/plan.md +0 -0
  167. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/research.md +0 -0
  168. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/spec.md +0 -0
  169. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/022-fix-regen-command/tasks.md +0 -0
  170. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/checklists/requirements.md +0 -0
  171. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/plan.md +0 -0
  172. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/research.md +0 -0
  173. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/spec.md +0 -0
  174. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/023-add-logging/tasks.md +0 -0
  175. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/checklists/requirements.md +0 -0
  176. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/plan.md +0 -0
  177. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/research.md +0 -0
  178. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/spec.md +0 -0
  179. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/024-validate-constants/tasks.md +0 -0
  180. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/checklists/requirements.md +0 -0
  181. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/plan.md +0 -0
  182. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/research.md +0 -0
  183. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/spec.md +0 -0
  184. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/025-harden-tests/tasks.md +0 -0
  185. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/checklists/requirements.md +0 -0
  186. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/contracts/orchestrator-contract.md +0 -0
  187. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/data-model.md +0 -0
  188. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/plan.md +0 -0
  189. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/quickstart.md +0 -0
  190. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/research.md +0 -0
  191. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/spec.md +0 -0
  192. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/specs/027-pipeline-auto-execution/tasks.md +0 -0
  193. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/agent-file-template.md +0 -0
  194. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/checklist-template.md +0 -0
  195. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/constitution-template.md +0 -0
  196. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/plan-template.md +0 -0
  197. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template-brownfield.md +0 -0
  198. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template-greenfield.md +0 -0
  199. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template-microservices.md +0 -0
  200. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/spec-template.md +0 -0
  201. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/.specify/templates/tasks-template.md +0 -0
  202. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/CLAUDE.md +0 -0
  203. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/CONTRIBUTING.md +0 -0
  204. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/LICENSE +0 -0
  205. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/README.md +0 -0
  206. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.context.md +0 -0
  207. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.extension.md +0 -0
  208. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.init.md +0 -0
  209. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.md +0 -0
  210. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.regen.md +0 -0
  211. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/commands/devflow.status.md +0 -0
  212. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/adr/0001-v4-workflow-compatibility.md +0 -0
  213. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/adr/0002-v5-rupture-and-provenance.md +0 -0
  214. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/commands-reference.md +0 -0
  215. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/cursor-guide.md +0 -0
  216. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/guides/brownfield.md +0 -0
  217. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/guides/greenfield.md +0 -0
  218. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/guides/microservices.md +0 -0
  219. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/index.md +0 -0
  220. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/pipeline-reference.generated.md +0 -0
  221. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/pipeline.md +0 -0
  222. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.0.md +0 -0
  223. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.1.md +0 -0
  224. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.3.md +0 -0
  225. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.4.md +0 -0
  226. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.5.md +0 -0
  227. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/4.0.6.md +0 -0
  228. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/5.0.0.md +0 -0
  229. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/releases/6.0.0.md +0 -0
  230. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/spec-driven.md +0 -0
  231. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/v5-decisions.md +0 -0
  232. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/docs/v6-decisions.md +0 -0
  233. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/EXTENSION-API-REFERENCE.md +0 -0
  234. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/catalog.community.json +0 -0
  235. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/catalog.json +0 -0
  236. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/template/example-command.md +0 -0
  237. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/extensions/template/example-extension.json +0 -0
  238. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/scripts/check_release.py +0 -0
  239. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/adapters/__init__.py +0 -0
  240. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/adapters/linear.py +0 -0
  241. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/__init__.py +0 -0
  242. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/assess.py +0 -0
  243. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/check.py +0 -0
  244. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/context.py +0 -0
  245. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/docs_sync.py +0 -0
  246. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/export_cmd.py +0 -0
  247. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/extension.py +0 -0
  248. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/feature.py +0 -0
  249. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/hooks_cmd.py +0 -0
  250. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/init_cmd.py +0 -0
  251. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/linear.py +0 -0
  252. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/stale.py +0 -0
  253. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/status.py +0 -0
  254. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/traceability.py +0 -0
  255. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/upgrade_cmd.py +0 -0
  256. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/commands/verify.py +0 -0
  257. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/__init__.py +0 -0
  258. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/activity_contracts.py +0 -0
  259. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/adaptive_runner.py +0 -0
  260. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/adaptive_workflow.py +0 -0
  261. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/agent_failure.py +0 -0
  262. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/assessment.py +0 -0
  263. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/automatic_evidence.py +0 -0
  264. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/catalog.py +0 -0
  265. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/contract_schemas.py +0 -0
  266. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/docgen.py +0 -0
  267. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/git.py +0 -0
  268. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/hooks.py +0 -0
  269. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/installer.py +0 -0
  270. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/manifest.py +0 -0
  271. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/omissions.py +0 -0
  272. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/operational.py +0 -0
  273. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/redaction.py +0 -0
  274. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/remediation.py +0 -0
  275. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/scanner.py +0 -0
  276. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/staleness.py +0 -0
  277. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/traceability.py +0 -0
  278. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/validation_approvals.py +0 -0
  279. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/validators.py +0 -0
  280. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/verification.py +0 -0
  281. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/waivers.py +0 -0
  282. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/worklog.py +0 -0
  283. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/core/worktree_snapshot.py +0 -0
  284. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/activity-contract-v3.schema.json +0 -0
  285. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/activity-result-v1.schema.json +0 -0
  286. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/assessment-v3.schema.json +0 -0
  287. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/schemas/workflow-state-v4.schema.json +0 -0
  288. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/__init__.py +0 -0
  289. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/console.py +0 -0
  290. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/logging.py +0 -0
  291. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/paths.py +0 -0
  292. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/src/devflow_cli/utils/strings.py +0 -0
  293. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/agent-context-template.md +0 -0
  294. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/constitution-template.md +0 -0
  295. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/README-template.md +0 -0
  296. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/api-template.md +0 -0
  297. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/components-template.md +0 -0
  298. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/interfaces-template.md +0 -0
  299. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts/services-template.md +0 -0
  300. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/contracts-template.md +0 -0
  301. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/data-model-template.md +0 -0
  302. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/devflow-hooks-template.yml +0 -0
  303. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/extension-manifest-template.json +0 -0
  304. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/plan-template.md +0 -0
  305. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/quickstart-template.md +0 -0
  306. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/research-template.md +0 -0
  307. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/spec-template.md +0 -0
  308. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/templates/tasks-template.md +0 -0
  309. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/fixtures/agents/mock-agent.md +0 -0
  310. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/fixtures/commands/mock-command.md +0 -0
  311. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/fixtures/mock-catalog.json +0 -0
  312. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/run-tests.sh +0 -0
  313. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test-helpers.sh +0 -0
  314. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test-template-variants.sh +0 -0
  315. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_activity_contracts.py +0 -0
  316. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_adaptive_runner.py +0 -0
  317. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_adaptive_workflow.py +0 -0
  318. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_agent_adapters.py +0 -0
  319. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_agent_failure.py +0 -0
  320. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_assessment.py +0 -0
  321. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_automatic_evidence.py +0 -0
  322. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_bash_runner.py +0 -0
  323. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_catalog.py +0 -0
  324. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_assess.py +0 -0
  325. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_check.py +0 -0
  326. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_context.py +0 -0
  327. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_docs_sync.py +0 -0
  328. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_extension.py +0 -0
  329. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_feature.py +0 -0
  330. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_hooks.py +0 -0
  331. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_init.py +0 -0
  332. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_linear.py +0 -0
  333. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_stale.py +0 -0
  334. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_status.py +0 -0
  335. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_traceability.py +0 -0
  336. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_upgrade.py +0 -0
  337. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_cmd_verify.py +0 -0
  338. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_constants.py +0 -0
  339. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_context.py +0 -0
  340. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_contract_schemas.py +0 -0
  341. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_docgen.py +0 -0
  342. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_git.py +0 -0
  343. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_hooks.py +0 -0
  344. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_installer.py +0 -0
  345. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_integration.py +0 -0
  346. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_linear_adapter.py +0 -0
  347. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_linear_order.py +0 -0
  348. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_logging.py +0 -0
  349. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_manifest.py +0 -0
  350. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_omissions.py +0 -0
  351. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_paths.py +0 -0
  352. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_paths_project_root.py +0 -0
  353. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_release.py +0 -0
  354. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_remediation.py +0 -0
  355. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_scanner.py +0 -0
  356. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_staleness.py +0 -0
  357. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_traceability.py +0 -0
  358. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_validators.py +0 -0
  359. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_verification.py +0 -0
  360. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_version.py +0 -0
  361. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_waivers.py +0 -0
  362. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_wheel_adaptive_acceptance.py +0 -0
  363. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_wheel_install.py +0 -0
  364. {devflow_cli-6.0.0 → devflow_cli-6.1.0}/tests/test_worklog.py +0 -0
  365. {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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: devflow-cli
3
- Version: 6.0.0
3
+ Version: 6.1.0
4
4
  Summary: Spec-Driven Development workflow CLI
5
5
  Project-URL: Homepage, https://github.com/sopequenoteck/devflow
6
6
  Project-URL: Repository, https://github.com/sopequenoteck/devflow
@@ -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.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "devflow-cli"
7
- version = "6.0.0"
7
+ version = "6.1.0"
8
8
  description = "Spec-Driven Development workflow CLI"
9
9
  requires-python = ">=3.11"
10
10
  license = {text = "MIT"}
@@ -1,6 +1,6 @@
1
1
  """devflow CLI — workflow de développement adaptatif."""
2
2
 
3
- VERSION = "6.0.0"
3
+ VERSION = "6.1.0"
4
4
 
5
5
  SUPPORTED_AGENTS = ["claude-code", "codex", "cursor"]
6
6
 
@@ -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
- _text(exc.stdout),
197
- _text(exc.stderr),
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__":