@pjmendonca/devflow 1.13.2 → 1.19.0

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 (236) hide show
  1. package/.claude/commands/agent.md +1 -1
  2. package/.claude/commands/brainstorm.md +28 -0
  3. package/.claude/commands/bugfix.md +21 -0
  4. package/.claude/commands/checkpoint.md +0 -1
  5. package/.claude/commands/collab.md +0 -1
  6. package/.claude/commands/costs.md +88 -18
  7. package/.claude/commands/devflow.md +26 -0
  8. package/.claude/commands/handoff.md +0 -1
  9. package/.claude/commands/init.md +383 -0
  10. package/.claude/commands/memory.md +0 -1
  11. package/.claude/commands/pair.md +0 -1
  12. package/.claude/commands/review.md +27 -0
  13. package/.claude/commands/route.md +0 -1
  14. package/.claude/commands/swarm.md +0 -1
  15. package/.claude/commands/validate.md +55 -0
  16. package/.claude/hooks/session-notification.sh +44 -0
  17. package/.claude/hooks/session-startup.sh +427 -0
  18. package/.claude/hooks/session-stop.sh +38 -0
  19. package/.claude/hooks/session_tracker.py +272 -0
  20. package/.claude/settings.json +38 -0
  21. package/.claude/skills/brainstorm/SKILL.md +531 -0
  22. package/.claude/skills/costs/SKILL.md +156 -0
  23. package/.claude/skills/validate/SKILL.md +101 -0
  24. package/CHANGELOG.md +284 -0
  25. package/README.md +207 -10
  26. package/bin/devflow-install.js +2 -1
  27. package/bin/devflow.js +4 -0
  28. package/lib/constants.js +0 -1
  29. package/lib/exec-python.js +1 -1
  30. package/package.json +1 -1
  31. package/tooling/.automation/.checkpoint_lock +1 -0
  32. package/tooling/.automation/agents/architect.md +19 -0
  33. package/tooling/.automation/agents/ba.md +19 -0
  34. package/tooling/.automation/agents/maintainer.md +19 -0
  35. package/tooling/.automation/agents/pm.md +19 -0
  36. package/tooling/.automation/agents/reviewer.md +1 -1
  37. package/tooling/.automation/agents/writer.md +19 -0
  38. package/tooling/.automation/benchmarks/benchmark_20251230_100119.json +314 -0
  39. package/tooling/.automation/benchmarks/benchmark_20251230_100216.json +314 -0
  40. package/tooling/.automation/costs/config.json +31 -0
  41. package/tooling/.automation/costs/sessions/2025-12-29_20251229_164128.json +22 -0
  42. package/tooling/.automation/memory/knowledge/kg_integration-test.json +738 -1
  43. package/tooling/.automation/memory/knowledge/kg_test-story.json +3381 -2
  44. package/tooling/.automation/memory/shared/shared_integration-test.json +193 -1
  45. package/tooling/.automation/memory/shared/shared_test-story.json +757 -1
  46. package/tooling/.automation/memory/shared/shared_test.json +1332 -0
  47. package/tooling/.automation/memory/shared/shared_validation-check.json +240 -0
  48. package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +5 -5
  49. package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +23 -5
  50. package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +24 -6
  51. package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +4 -4
  52. package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +4 -4
  53. package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +4 -4
  54. package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +18 -0
  55. package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +19 -1
  56. package/tooling/.automation/overrides/templates/dev/security-focused.yaml +18 -0
  57. package/tooling/.automation/overrides/templates/dev/user-advocate.yaml +54 -0
  58. package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +4 -4
  59. package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +4 -4
  60. package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +4 -4
  61. package/tooling/.automation/overrides/templates/maintainer/reliability-engineer.yaml +55 -0
  62. package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +4 -4
  63. package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +3 -3
  64. package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +4 -4
  65. package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +18 -0
  66. package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +18 -0
  67. package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +2 -2
  68. package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +3 -3
  69. package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +5 -5
  70. package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +4 -4
  71. package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +5 -5
  72. package/tooling/.automation/validation/history/2025-12-29_val_002a28c1.json +32 -0
  73. package/tooling/.automation/validation/history/2025-12-29_val_01273bb1.json +32 -0
  74. package/tooling/.automation/validation/history/2025-12-29_val_03369914.json +41 -0
  75. package/tooling/.automation/validation/history/2025-12-29_val_07a449ba.json +32 -0
  76. package/tooling/.automation/validation/history/2025-12-29_val_0df1f0a2.json +41 -0
  77. package/tooling/.automation/validation/history/2025-12-29_val_10ff3d34.json +41 -0
  78. package/tooling/.automation/validation/history/2025-12-29_val_110771d7.json +32 -0
  79. package/tooling/.automation/validation/history/2025-12-29_val_13f3a7f9.json +32 -0
  80. package/tooling/.automation/validation/history/2025-12-29_val_17ba9d21.json +41 -0
  81. package/tooling/.automation/validation/history/2025-12-29_val_22247089.json +32 -0
  82. package/tooling/.automation/validation/history/2025-12-29_val_227ea6a4.json +32 -0
  83. package/tooling/.automation/validation/history/2025-12-29_val_2335d5ae.json +32 -0
  84. package/tooling/.automation/validation/history/2025-12-29_val_246824bb.json +41 -0
  85. package/tooling/.automation/validation/history/2025-12-29_val_28b4b9cd.json +32 -0
  86. package/tooling/.automation/validation/history/2025-12-29_val_2abd12cc.json +32 -0
  87. package/tooling/.automation/validation/history/2025-12-29_val_2c801b2f.json +59 -0
  88. package/tooling/.automation/validation/history/2025-12-29_val_2c8cfa8e.json +32 -0
  89. package/tooling/.automation/validation/history/2025-12-29_val_2ce76eb0.json +32 -0
  90. package/tooling/.automation/validation/history/2025-12-29_val_30351948.json +41 -0
  91. package/tooling/.automation/validation/history/2025-12-29_val_30eb7229.json +41 -0
  92. package/tooling/.automation/validation/history/2025-12-29_val_34df0e77.json +41 -0
  93. package/tooling/.automation/validation/history/2025-12-29_val_376e4d6a.json +32 -0
  94. package/tooling/.automation/validation/history/2025-12-29_val_3a4e8a1a.json +59 -0
  95. package/tooling/.automation/validation/history/2025-12-29_val_3b77a628.json +32 -0
  96. package/tooling/.automation/validation/history/2025-12-29_val_3ea4e1cf.json +59 -0
  97. package/tooling/.automation/validation/history/2025-12-29_val_44aacdb4.json +59 -0
  98. package/tooling/.automation/validation/history/2025-12-29_val_457ddfa8.json +32 -0
  99. package/tooling/.automation/validation/history/2025-12-29_val_45af6238.json +41 -0
  100. package/tooling/.automation/validation/history/2025-12-29_val_4735dba1.json +41 -0
  101. package/tooling/.automation/validation/history/2025-12-29_val_486b203c.json +41 -0
  102. package/tooling/.automation/validation/history/2025-12-29_val_49dc56cd.json +59 -0
  103. package/tooling/.automation/validation/history/2025-12-29_val_4d863d6d.json +32 -0
  104. package/tooling/.automation/validation/history/2025-12-29_val_5149a808.json +59 -0
  105. package/tooling/.automation/validation/history/2025-12-29_val_52e0bb43.json +32 -0
  106. package/tooling/.automation/validation/history/2025-12-29_val_585d6319.json +59 -0
  107. package/tooling/.automation/validation/history/2025-12-29_val_5b2d859a.json +32 -0
  108. package/tooling/.automation/validation/history/2025-12-29_val_635a7081.json +41 -0
  109. package/tooling/.automation/validation/history/2025-12-29_val_64df4905.json +32 -0
  110. package/tooling/.automation/validation/history/2025-12-29_val_70634cee.json +41 -0
  111. package/tooling/.automation/validation/history/2025-12-29_val_714553f9.json +32 -0
  112. package/tooling/.automation/validation/history/2025-12-29_val_7f7bfdbf.json +41 -0
  113. package/tooling/.automation/validation/history/2025-12-29_val_7faad91d.json +32 -0
  114. package/tooling/.automation/validation/history/2025-12-29_val_81821f8f.json +41 -0
  115. package/tooling/.automation/validation/history/2025-12-29_val_8249f3c9.json +32 -0
  116. package/tooling/.automation/validation/history/2025-12-29_val_8422b50f.json +41 -0
  117. package/tooling/.automation/validation/history/2025-12-29_val_8446c134.json +32 -0
  118. package/tooling/.automation/validation/history/2025-12-29_val_879f4e26.json +59 -0
  119. package/tooling/.automation/validation/history/2025-12-29_val_8b6d5bd7.json +32 -0
  120. package/tooling/.automation/validation/history/2025-12-29_val_8c5cd787.json +32 -0
  121. package/tooling/.automation/validation/history/2025-12-29_val_91d20bc7.json +32 -0
  122. package/tooling/.automation/validation/history/2025-12-29_val_958a12b7.json +41 -0
  123. package/tooling/.automation/validation/history/2025-12-29_val_95d91108.json +41 -0
  124. package/tooling/.automation/validation/history/2025-12-29_val_980dbb74.json +32 -0
  125. package/tooling/.automation/validation/history/2025-12-29_val_9e40c79b.json +32 -0
  126. package/tooling/.automation/validation/history/2025-12-29_val_9f499b7c.json +32 -0
  127. package/tooling/.automation/validation/history/2025-12-29_val_9f7c3b57.json +32 -0
  128. package/tooling/.automation/validation/history/2025-12-29_val_a30d5bd4.json +32 -0
  129. package/tooling/.automation/validation/history/2025-12-29_val_a6eb09c7.json +32 -0
  130. package/tooling/.automation/validation/history/2025-12-29_val_a86f7b83.json +41 -0
  131. package/tooling/.automation/validation/history/2025-12-29_val_ad5347e1.json +41 -0
  132. package/tooling/.automation/validation/history/2025-12-29_val_b0a5a993.json +32 -0
  133. package/tooling/.automation/validation/history/2025-12-29_val_bcb0192e.json +32 -0
  134. package/tooling/.automation/validation/history/2025-12-29_val_bf3c9aaa.json +32 -0
  135. package/tooling/.automation/validation/history/2025-12-29_val_c461ff88.json +32 -0
  136. package/tooling/.automation/validation/history/2025-12-29_val_c4f4e258.json +41 -0
  137. package/tooling/.automation/validation/history/2025-12-29_val_c7f0fa6d.json +41 -0
  138. package/tooling/.automation/validation/history/2025-12-29_val_c911b0e6.json +32 -0
  139. package/tooling/.automation/validation/history/2025-12-29_val_cc581964.json +32 -0
  140. package/tooling/.automation/validation/history/2025-12-29_val_cdd5a33b.json +32 -0
  141. package/tooling/.automation/validation/history/2025-12-29_val_cfd42495.json +32 -0
  142. package/tooling/.automation/validation/history/2025-12-29_val_d1c7a4ee.json +41 -0
  143. package/tooling/.automation/validation/history/2025-12-29_val_d2280d0e.json +32 -0
  144. package/tooling/.automation/validation/history/2025-12-29_val_d2a6ff69.json +32 -0
  145. package/tooling/.automation/validation/history/2025-12-29_val_d8c53ab2.json +59 -0
  146. package/tooling/.automation/validation/history/2025-12-29_val_d9c1247a.json +41 -0
  147. package/tooling/.automation/validation/history/2025-12-29_val_d9d58569.json +32 -0
  148. package/tooling/.automation/validation/history/2025-12-29_val_dabb4fd9.json +32 -0
  149. package/tooling/.automation/validation/history/2025-12-29_val_dd8fe359.json +32 -0
  150. package/tooling/.automation/validation/history/2025-12-29_val_decdffc9.json +32 -0
  151. package/tooling/.automation/validation/history/2025-12-29_val_e3a95476.json +59 -0
  152. package/tooling/.automation/validation/history/2025-12-29_val_e776dfca.json +32 -0
  153. package/tooling/.automation/validation/history/2025-12-29_val_ea70969f.json +59 -0
  154. package/tooling/.automation/validation/history/2025-12-29_val_ef41ea95.json +32 -0
  155. package/tooling/.automation/validation/history/2025-12-29_val_f384f9b1.json +32 -0
  156. package/tooling/.automation/validation/history/2025-12-29_val_f8adc38c.json +41 -0
  157. package/tooling/.automation/validation/history/2025-12-29_val_fa40b69e.json +32 -0
  158. package/tooling/.automation/validation/history/2025-12-29_val_fc538d54.json +41 -0
  159. package/tooling/.automation/validation/history/2025-12-29_val_fe814665.json +32 -0
  160. package/tooling/.automation/validation/history/2025-12-29_val_ffea4b12.json +32 -0
  161. package/tooling/.automation/validation/history/2025-12-30_val_02d001e5.json +59 -0
  162. package/tooling/.automation/validation/history/2025-12-30_val_0b8966dc.json +32 -0
  163. package/tooling/.automation/validation/history/2025-12-30_val_15455fbf.json +59 -0
  164. package/tooling/.automation/validation/history/2025-12-30_val_157e34b9.json +32 -0
  165. package/tooling/.automation/validation/history/2025-12-30_val_28d1d933.json +32 -0
  166. package/tooling/.automation/validation/history/2025-12-30_val_3442a52c.json +32 -0
  167. package/tooling/.automation/validation/history/2025-12-30_val_37f1ce1e.json +32 -0
  168. package/tooling/.automation/validation/history/2025-12-30_val_4f1d8a93.json +32 -0
  169. package/tooling/.automation/validation/history/2025-12-30_val_56ff1de3.json +32 -0
  170. package/tooling/.automation/validation/history/2025-12-30_val_664fd4e2.json +41 -0
  171. package/tooling/.automation/validation/history/2025-12-30_val_66afb0a7.json +32 -0
  172. package/tooling/.automation/validation/history/2025-12-30_val_7634663c.json +41 -0
  173. package/tooling/.automation/validation/history/2025-12-30_val_8ea830c3.json +41 -0
  174. package/tooling/.automation/validation/history/2025-12-30_val_998957c2.json +32 -0
  175. package/tooling/.automation/validation/history/2025-12-30_val_a52177db.json +32 -0
  176. package/tooling/.automation/validation/history/2025-12-30_val_a5b65a63.json +32 -0
  177. package/tooling/.automation/validation/history/2025-12-30_val_ae391d0e.json +32 -0
  178. package/tooling/.automation/validation/history/2025-12-30_val_c7895339.json +41 -0
  179. package/tooling/.automation/validation/history/2025-12-30_val_ca416593.json +41 -0
  180. package/tooling/.automation/validation/history/2025-12-30_val_cee19422.json +32 -0
  181. package/tooling/.automation/validation/history/2025-12-30_val_ddd4f4e6.json +32 -0
  182. package/tooling/.automation/validation/history/2025-12-30_val_f2e1394b.json +32 -0
  183. package/tooling/.automation/validation/history/2025-12-30_val_f4a7fa06.json +41 -0
  184. package/tooling/.automation/validation/history/2025-12-30_val_ffea3369.json +32 -0
  185. package/tooling/.automation/validation/history/2026-01-03_val_1287a74c.json +41 -0
  186. package/tooling/.automation/validation/history/2026-01-03_val_3b24071f.json +32 -0
  187. package/tooling/.automation/validation/history/2026-01-03_val_44d77573.json +32 -0
  188. package/tooling/.automation/validation/history/2026-01-03_val_5b31dc51.json +32 -0
  189. package/tooling/.automation/validation/history/2026-01-03_val_74267244.json +32 -0
  190. package/tooling/.automation/validation/history/2026-01-03_val_8b2d95c7.json +59 -0
  191. package/tooling/.automation/validation/history/2026-01-03_val_d875b297.json +41 -0
  192. package/tooling/.automation/validation-config.yaml +103 -0
  193. package/tooling/completions/DevflowCompletion.ps1 +21 -21
  194. package/tooling/completions/_run-story +3 -3
  195. package/tooling/completions/run-story-completion.bash +8 -8
  196. package/tooling/docs/DOC-STANDARD.md +14 -14
  197. package/tooling/docs/stories/.gitkeep +0 -0
  198. package/tooling/docs/templates/brainstorm-guide.md +314 -0
  199. package/tooling/docs/templates/migration-spec.md +4 -4
  200. package/tooling/docs/templates/story.md +66 -0
  201. package/tooling/scripts/context_checkpoint.py +5 -15
  202. package/tooling/scripts/cost_dashboard.py +610 -13
  203. package/tooling/scripts/create-persona.py +1 -12
  204. package/tooling/scripts/create-persona.sh +44 -44
  205. package/tooling/scripts/lib/__init__.py +12 -1
  206. package/tooling/scripts/lib/agent_handoff.py +11 -2
  207. package/tooling/scripts/lib/agent_router.py +31 -10
  208. package/tooling/scripts/lib/colors.py +106 -0
  209. package/tooling/scripts/lib/context_monitor.py +766 -0
  210. package/tooling/scripts/lib/cost_config.py +229 -10
  211. package/tooling/scripts/lib/cost_display.py +20 -45
  212. package/tooling/scripts/lib/cost_tracker.py +462 -15
  213. package/tooling/scripts/lib/currency_converter.py +28 -5
  214. package/tooling/scripts/lib/pair_programming.py +102 -3
  215. package/tooling/scripts/lib/personality_system.py +949 -0
  216. package/tooling/scripts/lib/platform.py +55 -0
  217. package/tooling/scripts/lib/shared_memory.py +9 -3
  218. package/tooling/scripts/lib/swarm_orchestrator.py +514 -75
  219. package/tooling/scripts/lib/validation_loop.py +1014 -0
  220. package/tooling/scripts/memory_summarize.py +9 -2
  221. package/tooling/scripts/new-doc.py +2 -9
  222. package/tooling/scripts/personalize_agent.py +1 -12
  223. package/tooling/scripts/rollback-migration.sh +60 -60
  224. package/tooling/scripts/run-collab.ps1 +16 -16
  225. package/tooling/scripts/run-collab.py +88 -53
  226. package/tooling/scripts/run-collab.sh +4 -4
  227. package/tooling/scripts/run-story.py +278 -20
  228. package/tooling/scripts/run-story.sh +3 -3
  229. package/tooling/scripts/setup-checkpoint-service.py +2 -9
  230. package/tooling/scripts/tech-debt-tracker.py +1 -12
  231. package/tooling/scripts/test_adversarial_swarm.py +452 -0
  232. package/tooling/scripts/validate-overrides.py +1 -10
  233. package/tooling/scripts/validate-overrides.sh +40 -40
  234. package/tooling/scripts/validate_loop.py +162 -0
  235. package/tooling/scripts/validate_setup.py +2 -30
  236. package/.claude/skills/init/SKILL.md +0 -496
@@ -0,0 +1,55 @@
1
+ # Validate
2
+
3
+ Run validation checks on the current story or codebase.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ /validate [story-key] [options]
9
+ ```
10
+
11
+ ## Options
12
+
13
+ - `--tier 1|2|3|all` - Which validation tier to run
14
+ - 1: Pre-flight (story exists, budget, dependencies)
15
+ - 2: Inter-phase (code compiles, lint, transitions)
16
+ - 3: Post-completion (tests, types, version sync)
17
+ - all: Run all tiers
18
+ - `--auto-fix` - Attempt automatic fixes for failures
19
+ - `--json` - Output as JSON
20
+ - `--quiet` - Minimal output
21
+
22
+ ## Examples
23
+
24
+ ```bash
25
+ # Run all validation tiers
26
+ /validate 3-5 --tier all
27
+
28
+ # Run pre-flight checks only
29
+ /validate 3-5 --tier 1
30
+
31
+ # Run post-completion with auto-fix
32
+ /validate 3-5 --tier 3 --auto-fix
33
+ ```
34
+
35
+ ## Prompt
36
+
37
+ Run the validation loop for story: $ARGUMENTS
38
+
39
+ Execute the following:
40
+
41
+ ```bash
42
+ python3 tooling/scripts/lib/validation_loop.py --story "$ARGUMENTS" --all
43
+ ```
44
+
45
+ If no story key is provided, run validation on the current codebase state:
46
+
47
+ ```bash
48
+ python3 tooling/scripts/lib/validation_loop.py --tier 3
49
+ ```
50
+
51
+ Report the validation results clearly, including:
52
+ - Which gates passed
53
+ - Which gates failed with reasons
54
+ - Any warnings
55
+ - Suggested fixes if available
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+ # Session Notification Hook - Captures token usage from Claude Code notifications
3
+
4
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
5
+ TRACKER="$PROJECT_DIR/.claude/hooks/session_tracker.py"
6
+
7
+ # Read notification data from Claude Code
8
+ INPUT=$(cat)
9
+
10
+ # Try to extract token usage from notification
11
+ # Claude Code may send usage data in various formats
12
+ INPUT_TOKENS=$(echo "$INPUT" | jq -r '
13
+ .usage.input_tokens //
14
+ .data.usage.input_tokens //
15
+ .message.usage.input_tokens //
16
+ .input_tokens //
17
+ 0
18
+ ' 2>/dev/null)
19
+
20
+ OUTPUT_TOKENS=$(echo "$INPUT" | jq -r '
21
+ .usage.output_tokens //
22
+ .data.usage.output_tokens //
23
+ .message.usage.output_tokens //
24
+ .output_tokens //
25
+ 0
26
+ ' 2>/dev/null)
27
+
28
+ MODEL=$(echo "$INPUT" | jq -r '
29
+ .model //
30
+ .data.model //
31
+ .message.model //
32
+ ""
33
+ ' 2>/dev/null)
34
+
35
+ # Only log if we have actual token data
36
+ if [ "$INPUT_TOKENS" -gt 0 ] 2>/dev/null || [ "$OUTPUT_TOKENS" -gt 0 ] 2>/dev/null; then
37
+ if [ -n "$MODEL" ] && [ "$MODEL" != "null" ]; then
38
+ python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" --model "$MODEL" 2>/dev/null
39
+ else
40
+ python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" 2>/dev/null
41
+ fi
42
+ fi
43
+
44
+ exit 0
@@ -0,0 +1,427 @@
1
+ #!/bin/bash
2
+ # Devflow Session Startup Hook
3
+ # Automatically loads plans and context when Claude Code starts
4
+
5
+ # Read input from Claude Code (contains model info)
6
+ INPUT=$(cat)
7
+
8
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
9
+ TRACKER="$PROJECT_DIR/.claude/hooks/session_tracker.py"
10
+ PLANS_DIR="$PROJECT_DIR/.claude/plans"
11
+ SESSIONS_DIR="$PROJECT_DIR/tooling/.automation/costs/sessions"
12
+ MEMORY_DIR="$PROJECT_DIR/tooling/.automation/memory"
13
+ CONTEXT_DIR="$PROJECT_DIR/tooling/.automation/context"
14
+ COST_CONFIG="$PROJECT_DIR/tooling/.automation/costs/config.json"
15
+
16
+ # Ensure plans directory exists
17
+ mkdir -p "$PLANS_DIR" 2>/dev/null
18
+
19
+ # Start session tracking
20
+ MODEL_NAME=$(echo "$INPUT" | jq -r '.model.name // .model // ""' 2>/dev/null)
21
+ if [ -n "$MODEL_NAME" ] && [ "$MODEL_NAME" != "null" ]; then
22
+ python3 "$TRACKER" start --model "$MODEL_NAME" 2>/dev/null
23
+ else
24
+ python3 "$TRACKER" start 2>/dev/null
25
+ fi
26
+
27
+ echo "[DEVFLOW SESSION START]"
28
+ echo ""
29
+
30
+ # ============================================================================
31
+ # CUMULATIVE USAGE DISPLAY
32
+ # ============================================================================
33
+
34
+ calc_cumulative_usage() {
35
+ local billing_period=${1:-30}
36
+ local total_tokens=0
37
+ local total_cost=0
38
+ local session_count=0
39
+
40
+ if [ -d "$SESSIONS_DIR" ]; then
41
+ CUTOFF_DATE=$(date -v-${billing_period}d +%Y-%m-%d 2>/dev/null || date -d "-${billing_period} days" +%Y-%m-%d 2>/dev/null)
42
+
43
+ for session_file in "$SESSIONS_DIR"/*.json; do
44
+ [ -f "$session_file" ] || continue
45
+ FILE_DATE=$(basename "$session_file" | cut -d'_' -f1)
46
+
47
+ if [[ "$FILE_DATE" > "$CUTOFF_DATE" ]] || [[ "$FILE_DATE" == "$CUTOFF_DATE" ]]; then
48
+ SESSION_TOKENS=$(jq -r '.totals.total_tokens // 0' "$session_file" 2>/dev/null)
49
+ SESSION_COST=$(jq -r '.totals.cost_usd // 0' "$session_file" 2>/dev/null)
50
+
51
+ total_tokens=$((total_tokens + SESSION_TOKENS))
52
+ total_cost=$(echo "$total_cost + $SESSION_COST" | bc 2>/dev/null || echo "$total_cost")
53
+ session_count=$((session_count + 1))
54
+ fi
55
+ done
56
+ fi
57
+
58
+ echo "$total_tokens|$total_cost|$session_count"
59
+ }
60
+
61
+ # Get cumulative usage
62
+ CUMULATIVE=$(calc_cumulative_usage 30)
63
+ CUM_TOKENS=$(echo "$CUMULATIVE" | cut -d'|' -f1)
64
+ CUM_COST=$(echo "$CUMULATIVE" | cut -d'|' -f2)
65
+ CUM_SESSIONS=$(echo "$CUMULATIVE" | cut -d'|' -f3)
66
+
67
+ # Add baseline to cumulative
68
+ BASELINE_TOKENS=$(jq -r '.baseline_tokens // 0' "$COST_CONFIG" 2>/dev/null)
69
+ BASELINE_COST=$(jq -r '.baseline_cost // 0' "$COST_CONFIG" 2>/dev/null)
70
+ CUM_TOKENS=$((CUM_TOKENS + BASELINE_TOKENS))
71
+ CUM_COST=$(echo "$CUM_COST + $BASELINE_COST" | bc 2>/dev/null || echo "$CUM_COST")
72
+
73
+ # Format tokens for display
74
+ format_tokens() {
75
+ local tokens=$1
76
+ if [ "$tokens" -ge 1000000 ] 2>/dev/null; then
77
+ echo "$(echo "scale=1; $tokens / 1000000" | bc 2>/dev/null || echo "$tokens")M"
78
+ elif [ "$tokens" -ge 1000 ] 2>/dev/null; then
79
+ echo "$(echo "scale=1; $tokens / 1000" | bc 2>/dev/null || echo "$tokens")K"
80
+ else
81
+ echo "$tokens"
82
+ fi
83
+ }
84
+
85
+ CUM_TOKENS_FMT=$(format_tokens "$CUM_TOKENS")
86
+ CUM_COST_FMT=$(printf "%.2f" "$CUM_COST" 2>/dev/null || echo "$CUM_COST")
87
+
88
+ if [ "$CUM_SESSIONS" -gt 0 ] 2>/dev/null; then
89
+ echo "[CUMULATIVE USAGE] Last 30 days: ${CUM_TOKENS_FMT} tokens | \$${CUM_COST_FMT} | ${CUM_SESSIONS} sessions"
90
+ echo ""
91
+ fi
92
+
93
+ # ============================================================================
94
+ # SUBSCRIPTION PLAN DETECTION
95
+ # ============================================================================
96
+
97
+ # Extract model from input
98
+ MODEL=$(echo "$INPUT" | jq -r '.model.display_name // .model.name // .model // ""' 2>/dev/null)
99
+
100
+ # Token limits by plan
101
+ get_token_limit() {
102
+ case "$1" in
103
+ free) echo 100000 ;;
104
+ developer) echo 1000000 ;;
105
+ pro) echo 5000000 ;;
106
+ scale) echo 20000000 ;;
107
+ enterprise) echo 100000000 ;;
108
+ *) echo 1000000 ;;
109
+ esac
110
+ }
111
+
112
+ # Detect plan from model
113
+ detect_plan_from_model() {
114
+ local model_lower=$(echo "$1" | tr '[:upper:]' '[:lower:]')
115
+ case "$model_lower" in
116
+ *opus*) echo "pro" ;;
117
+ *sonnet*) echo "developer" ;;
118
+ *haiku*) echo "free" ;;
119
+ *) echo "developer" ;;
120
+ esac
121
+ }
122
+
123
+ # Ensure config directory exists
124
+ mkdir -p "$(dirname "$COST_CONFIG")" 2>/dev/null
125
+
126
+ # Check if config exists, create if not
127
+ if [ ! -f "$COST_CONFIG" ]; then
128
+ echo '{"display_currency": "USD", "currency_rates": {"USD": 1.0}}' > "$COST_CONFIG"
129
+ fi
130
+
131
+ # Read current plan from config
132
+ CURRENT_PLAN=$(jq -r '.subscription_plan // ""' "$COST_CONFIG" 2>/dev/null)
133
+
134
+ # Detect plan based on model if not already configured
135
+ if [ -z "$CURRENT_PLAN" ] && [ -n "$MODEL" ]; then
136
+ DETECTED_PLAN=$(detect_plan_from_model "$MODEL")
137
+ TOKEN_LIMIT=$(get_token_limit "$DETECTED_PLAN")
138
+
139
+ # Save to config
140
+ TMP_CONFIG=$(mktemp)
141
+ jq --arg plan "$DETECTED_PLAN" --argjson limit "$TOKEN_LIMIT" \
142
+ '.subscription_plan = $plan | .subscription_token_limit = $limit' \
143
+ "$COST_CONFIG" > "$TMP_CONFIG" 2>/dev/null && \
144
+ mv "$TMP_CONFIG" "$COST_CONFIG" 2>/dev/null || rm -f "$TMP_CONFIG"
145
+
146
+ CURRENT_PLAN="$DETECTED_PLAN"
147
+ echo "[SUBSCRIPTION] Auto-detected plan: $DETECTED_PLAN ($(get_token_limit "$DETECTED_PLAN" | numfmt --to=si 2>/dev/null || echo "$(get_token_limit "$DETECTED_PLAN")") tokens/month)"
148
+ echo ""
149
+ elif [ -n "$CURRENT_PLAN" ]; then
150
+ TOKEN_LIMIT=$(jq -r '.subscription_token_limit // 0' "$COST_CONFIG" 2>/dev/null)
151
+ if [ "$TOKEN_LIMIT" -gt 0 ] 2>/dev/null; then
152
+ # Calculate current usage
153
+ BILLING_PERIOD=$(jq -r '.subscription_billing_period_days // 30' "$COST_CONFIG" 2>/dev/null)
154
+ CUTOFF_DATE=$(date -v-${BILLING_PERIOD}d +%Y-%m-%d 2>/dev/null || date -d "-${BILLING_PERIOD} days" +%Y-%m-%d 2>/dev/null)
155
+
156
+ TOTAL_TOKENS=0
157
+ if [ -d "$SESSIONS_DIR" ]; then
158
+ for session_file in "$SESSIONS_DIR"/*.json; do
159
+ [ -f "$session_file" ] || continue
160
+ FILE_DATE=$(basename "$session_file" | cut -d'_' -f1)
161
+ if [[ "$FILE_DATE" > "$CUTOFF_DATE" ]] || [[ "$FILE_DATE" == "$CUTOFF_DATE" ]]; then
162
+ SESSION_TOKENS=$(jq -r '.totals.total_tokens // 0' "$session_file" 2>/dev/null)
163
+ TOTAL_TOKENS=$((TOTAL_TOKENS + SESSION_TOKENS))
164
+ fi
165
+ done
166
+ fi
167
+
168
+ USAGE_PERCENT=$(echo "scale=1; ($TOTAL_TOKENS * 100) / $TOKEN_LIMIT" | bc 2>/dev/null || echo "0")
169
+ echo "[SUBSCRIPTION] Plan: $CURRENT_PLAN | Usage: ${USAGE_PERCENT}% of $(echo "$TOKEN_LIMIT" | numfmt --to=si 2>/dev/null || echo "$TOKEN_LIMIT") tokens"
170
+ echo ""
171
+ fi
172
+ fi
173
+
174
+ # ============================================================================
175
+ # BASELINE USAGE SETUP (First-time only)
176
+ # ============================================================================
177
+
178
+ setup_baseline() {
179
+ # Check if baseline has been configured
180
+ BASELINE_CONFIGURED=$(jq -r '.baseline_configured // false' "$COST_CONFIG" 2>/dev/null)
181
+
182
+ if [ "$BASELINE_CONFIGURED" = "true" ]; then
183
+ return 0
184
+ fi
185
+
186
+ # Check if we have a real interactive terminal
187
+ # Hooks run non-interactively, so we auto-configure with defaults
188
+ if [ ! -t 0 ] || [ -z "$(tty 2>/dev/null)" ] || [ "$(tty 2>/dev/null)" = "not a tty" ]; then
189
+ # Non-interactive: auto-configure with defaults
190
+ BASELINE_TOKENS=0
191
+ BASELINE_COST=0
192
+
193
+ # Save to config
194
+ TMP_CONFIG=$(mktemp)
195
+ jq --argjson tokens "$BASELINE_TOKENS" \
196
+ --argjson cost "$BASELINE_COST" \
197
+ --argjson configured true \
198
+ '.baseline_tokens = $tokens | .baseline_cost = $cost | .baseline_configured = $configured' \
199
+ "$COST_CONFIG" > "$TMP_CONFIG" 2>/dev/null && \
200
+ mv "$TMP_CONFIG" "$COST_CONFIG" 2>/dev/null || rm -f "$TMP_CONFIG"
201
+
202
+ echo "[OK] Baseline auto-configured (starting fresh). Run 'devflow baseline' to adjust."
203
+ return 0
204
+ fi
205
+
206
+ echo ""
207
+ echo "============================================================"
208
+ echo " USAGE TRACKING SETUP"
209
+ echo "============================================================"
210
+ echo ""
211
+ echo "Devflow tracks your Claude Code usage across sessions."
212
+ echo "Since this is your first time, we need to set a baseline."
213
+ echo ""
214
+ echo "Options:"
215
+ echo " 1) Start fresh - Begin tracking from 0 (recommended for new billing periods)"
216
+ echo " 2) Set baseline - Enter your current usage from Claude Console"
217
+ echo ""
218
+
219
+ # Read user choice with timeout to prevent hanging
220
+ if read -r -t 5 -p "Choose an option [1/2]: " choice </dev/tty 2>/dev/null; then
221
+ case "$choice" in
222
+ 2)
223
+ echo ""
224
+ echo "Enter your current token usage (e.g., 500000 or 500K or 1.5M):"
225
+ read -r -t 30 -p "Tokens: " token_input </dev/tty
226
+
227
+ # Parse token input (handle K/M suffixes)
228
+ BASELINE_TOKENS=$(echo "$token_input" | awk '{
229
+ gsub(/,/, "");
230
+ if (tolower($0) ~ /m$/) { gsub(/[mM]/, ""); print int($0 * 1000000) }
231
+ else if (tolower($0) ~ /k$/) { gsub(/[kK]/, ""); print int($0 * 1000) }
232
+ else { print int($0) }
233
+ }')
234
+
235
+ echo "Enter your current cost (e.g., 5.50):"
236
+ read -r -t 30 -p "Cost $: " cost_input </dev/tty
237
+ BASELINE_COST=$(echo "$cost_input" | sed 's/[$,]//g')
238
+
239
+ echo ""
240
+ echo "Setting baseline: ${BASELINE_TOKENS} tokens, \$${BASELINE_COST}"
241
+ ;;
242
+ *)
243
+ BASELINE_TOKENS=0
244
+ BASELINE_COST=0
245
+ echo ""
246
+ echo "Starting fresh with 0 baseline."
247
+ ;;
248
+ esac
249
+ else
250
+ # Timeout or no input - use defaults
251
+ BASELINE_TOKENS=0
252
+ BASELINE_COST=0
253
+ echo ""
254
+ echo "Starting fresh with 0 baseline (timeout)."
255
+ fi
256
+
257
+ # Save to config
258
+ TMP_CONFIG=$(mktemp)
259
+ jq --argjson tokens "$BASELINE_TOKENS" \
260
+ --argjson cost "$BASELINE_COST" \
261
+ --argjson configured true \
262
+ '.baseline_tokens = $tokens | .baseline_cost = $cost | .baseline_configured = $configured' \
263
+ "$COST_CONFIG" > "$TMP_CONFIG" 2>/dev/null && \
264
+ mv "$TMP_CONFIG" "$COST_CONFIG" 2>/dev/null || rm -f "$TMP_CONFIG"
265
+
266
+ echo ""
267
+ echo "[OK] Baseline configured. Your cumulative usage will now include this baseline."
268
+ echo "============================================================"
269
+ echo ""
270
+ }
271
+
272
+ # Always run setup_baseline - it handles non-interactive mode internally
273
+ setup_baseline
274
+
275
+ # Check for active plans (multiple locations)
276
+ detect_plans() {
277
+ local found_plans=()
278
+ local plan_details=()
279
+
280
+ # Location 1: Devflow plans directory
281
+ if [ -d "$PLANS_DIR" ]; then
282
+ while IFS= read -r -d '' plan; do
283
+ found_plans+=("$plan")
284
+ name=$(basename "$plan" .md)
285
+ # Get first line as description
286
+ desc=$(head -1 "$plan" 2>/dev/null | sed 's/^#* *//' | cut -c1-50)
287
+ plan_details+=("$name: $desc")
288
+ done < <(find "$PLANS_DIR" -name "*.md" -type f -print0 2>/dev/null)
289
+ fi
290
+
291
+ # Location 2: Claude Code plan files (look for plan.md or PLAN.md in project)
292
+ for plan_file in "$PROJECT_DIR/plan.md" "$PROJECT_DIR/PLAN.md" "$PROJECT_DIR/.claude/plan.md"; do
293
+ if [ -f "$plan_file" ]; then
294
+ found_plans+=("$plan_file")
295
+ name=$(basename "$plan_file" .md)
296
+ desc=$(head -1 "$plan_file" 2>/dev/null | sed 's/^#* *//' | cut -c1-50)
297
+ plan_details+=("$name: $desc")
298
+ fi
299
+ done
300
+
301
+ # Location 3: Check for recent plan mode files (Claude Code creates these)
302
+ if [ -d "$PROJECT_DIR/.claude" ]; then
303
+ while IFS= read -r -d '' plan; do
304
+ # Avoid duplicates
305
+ if [[ ! " ${found_plans[*]} " =~ " ${plan} " ]]; then
306
+ found_plans+=("$plan")
307
+ name=$(basename "$plan" .md)
308
+ modified=$(stat -f "%Sm" -t "%Y-%m-%d" "$plan" 2>/dev/null || stat -c "%y" "$plan" 2>/dev/null | cut -d' ' -f1)
309
+ plan_details+=("$name ($modified)")
310
+ fi
311
+ done < <(find "$PROJECT_DIR/.claude" -maxdepth 2 -name "*plan*.md" -type f -print0 2>/dev/null)
312
+ fi
313
+
314
+ # Output results
315
+ local count=${#found_plans[@]}
316
+ if [ "$count" -gt 0 ]; then
317
+ echo "[PLANS] Found $count plan(s):"
318
+ for detail in "${plan_details[@]}"; do
319
+ echo " - $detail"
320
+ done
321
+ echo ""
322
+ else
323
+ echo "[PLANS] No saved plans found"
324
+ echo ""
325
+ fi
326
+ }
327
+
328
+ detect_plans
329
+
330
+ # Check for recent sessions
331
+ if [ -d "$SESSIONS_DIR" ]; then
332
+ recent=$(ls -t "$SESSIONS_DIR" 2>/dev/null | head -1)
333
+ if [ -n "$recent" ]; then
334
+ echo "[SESSIONS] Most recent session: $recent"
335
+ # Try to extract story key from session file
336
+ if command -v jq >/dev/null 2>&1; then
337
+ if [ -f "$SESSIONS_DIR/$recent" ]; then
338
+ story_key=$(jq -r '.story_key // empty' "$SESSIONS_DIR/$recent" 2>/dev/null)
339
+ if [ -n "$story_key" ]; then
340
+ echo " Story: $story_key"
341
+ fi
342
+ fi
343
+ fi
344
+ echo ""
345
+ fi
346
+ fi
347
+
348
+ # Check for shared memory/knowledge
349
+ if [ -d "$MEMORY_DIR/shared" ]; then
350
+ count=$(find "$MEMORY_DIR/shared" -type f 2>/dev/null | wc -l | tr -d ' ')
351
+ if [ "$count" -gt 0 ]; then
352
+ echo "[MEMORY] $count shared memory file(s) available"
353
+ echo " Use /memory to view knowledge graph"
354
+ echo ""
355
+ fi
356
+ fi
357
+
358
+ # Check for context state
359
+ if [ -d "$CONTEXT_DIR" ]; then
360
+ ctx_count=$(find "$CONTEXT_DIR" -name "context_*.json" -type f 2>/dev/null | wc -l | tr -d ' ')
361
+ if [ "$ctx_count" -gt 0 ]; then
362
+ echo "[CONTEXT] Previous context state available"
363
+ find "$CONTEXT_DIR" -name "context_*.json" -type f 2>/dev/null | while read -r ctx; do
364
+ name=$(basename "$ctx" .json | sed 's/context_//')
365
+ if command -v jq >/dev/null 2>&1; then
366
+ usage=$(jq -r '.estimated_context_tokens // 0' "$ctx" 2>/dev/null)
367
+ if [ "$usage" != "0" ] && [ -n "$usage" ]; then
368
+ echo " - $name: ~$usage tokens"
369
+ fi
370
+ else
371
+ echo " - $name"
372
+ fi
373
+ done
374
+ echo ""
375
+ fi
376
+ fi
377
+
378
+ # ============================================================================
379
+ # STATUS BAR PREVIEW
380
+ # ============================================================================
381
+
382
+ # Build status bar preview
383
+ STATUS_BAR=""
384
+
385
+ # Extract model from input
386
+ MODEL=$(echo "$INPUT" | jq -r '.model.display_name // .model.name // .model // "Unknown"' 2>/dev/null)
387
+
388
+ # Get subscription info
389
+ if [ -f "$COST_CONFIG" ]; then
390
+ SUB_PLAN=$(jq -r '.subscription_plan // ""' "$COST_CONFIG" 2>/dev/null)
391
+ TOKEN_LIMIT=$(jq -r '.subscription_token_limit // 0' "$COST_CONFIG" 2>/dev/null)
392
+
393
+ if [ -n "$SUB_PLAN" ] && [ "$TOKEN_LIMIT" -gt 0 ] 2>/dev/null; then
394
+ USAGE_PCT=$(echo "scale=1; ($CUM_TOKENS * 100) / $TOKEN_LIMIT" | bc 2>/dev/null || echo "0")
395
+
396
+ # Color based on usage
397
+ if (( $(echo "$USAGE_PCT >= 90" | bc -l 2>/dev/null || echo 0) )); then
398
+ COLOR="\033[31m" # Red
399
+ elif (( $(echo "$USAGE_PCT >= 75" | bc -l 2>/dev/null || echo 0) )); then
400
+ COLOR="\033[33m" # Yellow
401
+ else
402
+ COLOR="\033[32m" # Green
403
+ fi
404
+ RESET="\033[0m"
405
+
406
+ TOKEN_LIMIT_FMT=$(format_tokens "$TOKEN_LIMIT")
407
+ STATUS_BAR="[Devflow] $MODEL | ${COLOR}Usage: ${USAGE_PCT}% (${CUM_TOKENS_FMT}/${TOKEN_LIMIT_FMT})${RESET} | Cost: \$${CUM_COST_FMT}"
408
+ else
409
+ STATUS_BAR="[Devflow] $MODEL | Tokens: ${CUM_TOKENS_FMT} | Cost: \$${CUM_COST_FMT}"
410
+ fi
411
+ else
412
+ STATUS_BAR="[Devflow] $MODEL | Tokens: ${CUM_TOKENS_FMT} | Cost: \$${CUM_COST_FMT}"
413
+ fi
414
+
415
+ echo "---"
416
+ echo -e "$STATUS_BAR"
417
+ echo "---"
418
+ echo ""
419
+
420
+ # Quick tips
421
+ echo "[QUICK START]"
422
+ echo " /story <key> - Run full story pipeline"
423
+ echo " /develop - Development phase only"
424
+ echo " /review - Code review only"
425
+ echo " /costs - View cost dashboard"
426
+
427
+ exit 0
@@ -0,0 +1,38 @@
1
+ #!/bin/bash
2
+ # Session Stop Hook - Saves session cost data when Claude Code stops
3
+
4
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
5
+ TRACKER="$PROJECT_DIR/.claude/hooks/session_tracker.py"
6
+
7
+ # Read input from Claude Code (contains stop reason, transcript summary)
8
+ INPUT=$(cat)
9
+
10
+ # Extract token info if available from the stop event
11
+ # The stop event may contain usage statistics
12
+ INPUT_TOKENS=$(echo "$INPUT" | jq -r '.usage.input_tokens // .transcript_summary.input_tokens // 0' 2>/dev/null)
13
+ OUTPUT_TOKENS=$(echo "$INPUT" | jq -r '.usage.output_tokens // .transcript_summary.output_tokens // 0' 2>/dev/null)
14
+ MODEL=$(echo "$INPUT" | jq -r '.model // ""' 2>/dev/null)
15
+
16
+ # Log final usage if we have token data
17
+ if [ "$INPUT_TOKENS" -gt 0 ] 2>/dev/null || [ "$OUTPUT_TOKENS" -gt 0 ] 2>/dev/null; then
18
+ if [ -n "$MODEL" ]; then
19
+ python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" --model "$MODEL" 2>/dev/null
20
+ else
21
+ python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" 2>/dev/null
22
+ fi
23
+ fi
24
+
25
+ # End the session and save
26
+ RESULT=$(python3 "$TRACKER" end 2>/dev/null)
27
+
28
+ # Output summary if session had activity
29
+ SAVED=$(echo "$RESULT" | jq -r '.saved // false' 2>/dev/null)
30
+ TOKENS=$(echo "$RESULT" | jq -r '.total_tokens // 0' 2>/dev/null)
31
+ COST=$(echo "$RESULT" | jq -r '.cost_usd // 0' 2>/dev/null)
32
+
33
+ if [ "$SAVED" = "true" ] 2>/dev/null; then
34
+ echo ""
35
+ echo "[SESSION SAVED] Tokens: $TOKENS | Cost: \$$COST"
36
+ fi
37
+
38
+ exit 0