@pjmendonca/devflow 1.13.1 → 1.18.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 (228) hide show
  1. package/.claude/commands/agent.md +1 -1
  2. package/.claude/commands/bugfix.md +21 -0
  3. package/.claude/commands/checkpoint.md +0 -1
  4. package/.claude/commands/collab.md +0 -1
  5. package/.claude/commands/costs.md +88 -18
  6. package/.claude/commands/devflow.md +26 -0
  7. package/.claude/commands/handoff.md +0 -1
  8. package/.claude/commands/memory.md +0 -1
  9. package/.claude/commands/pair.md +0 -1
  10. package/.claude/commands/review.md +27 -0
  11. package/.claude/commands/route.md +0 -1
  12. package/.claude/commands/swarm.md +0 -1
  13. package/.claude/commands/validate.md +55 -0
  14. package/.claude/hooks/session-notification.sh +44 -0
  15. package/.claude/hooks/session-startup.sh +427 -0
  16. package/.claude/hooks/session-stop.sh +38 -0
  17. package/.claude/hooks/session_tracker.py +272 -0
  18. package/.claude/settings.json +38 -0
  19. package/.claude/skills/costs/SKILL.md +156 -0
  20. package/.claude/skills/validate/SKILL.md +101 -0
  21. package/CHANGELOG.md +254 -0
  22. package/README.md +207 -10
  23. package/bin/devflow-install.js +2 -1
  24. package/bin/devflow.js +5 -2
  25. package/lib/constants.js +0 -1
  26. package/lib/exec-python.js +1 -1
  27. package/package.json +1 -2
  28. package/tooling/.automation/.checkpoint_lock +1 -0
  29. package/tooling/.automation/agents/architect.md +19 -0
  30. package/tooling/.automation/agents/ba.md +19 -0
  31. package/tooling/.automation/agents/maintainer.md +19 -0
  32. package/tooling/.automation/agents/pm.md +19 -0
  33. package/tooling/.automation/agents/reviewer.md +1 -1
  34. package/tooling/.automation/agents/writer.md +19 -0
  35. package/tooling/.automation/benchmarks/benchmark_20251230_100119.json +314 -0
  36. package/tooling/.automation/benchmarks/benchmark_20251230_100216.json +314 -0
  37. package/tooling/.automation/costs/config.json +31 -0
  38. package/tooling/.automation/costs/sessions/2025-12-29_20251229_164128.json +22 -0
  39. package/tooling/.automation/memory/knowledge/kg_integration-test.json +707 -1
  40. package/tooling/.automation/memory/knowledge/kg_test-story.json +3273 -2
  41. package/tooling/.automation/memory/shared/shared_integration-test.json +181 -1
  42. package/tooling/.automation/memory/shared/shared_test-story.json +721 -1
  43. package/tooling/.automation/memory/shared/shared_test.json +1254 -0
  44. package/tooling/.automation/memory/shared/shared_validation-check.json +227 -0
  45. package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +5 -5
  46. package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +23 -5
  47. package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +24 -6
  48. package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +4 -4
  49. package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +4 -4
  50. package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +4 -4
  51. package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +18 -0
  52. package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +19 -1
  53. package/tooling/.automation/overrides/templates/dev/security-focused.yaml +18 -0
  54. package/tooling/.automation/overrides/templates/dev/user-advocate.yaml +54 -0
  55. package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +4 -4
  56. package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +4 -4
  57. package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +4 -4
  58. package/tooling/.automation/overrides/templates/maintainer/reliability-engineer.yaml +55 -0
  59. package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +4 -4
  60. package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +3 -3
  61. package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +4 -4
  62. package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +18 -0
  63. package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +18 -0
  64. package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +2 -2
  65. package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +3 -3
  66. package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +5 -5
  67. package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +4 -4
  68. package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +5 -5
  69. package/tooling/.automation/validation/history/2025-12-29_val_002a28c1.json +32 -0
  70. package/tooling/.automation/validation/history/2025-12-29_val_01273bb1.json +32 -0
  71. package/tooling/.automation/validation/history/2025-12-29_val_03369914.json +41 -0
  72. package/tooling/.automation/validation/history/2025-12-29_val_07a449ba.json +32 -0
  73. package/tooling/.automation/validation/history/2025-12-29_val_0df1f0a2.json +41 -0
  74. package/tooling/.automation/validation/history/2025-12-29_val_10ff3d34.json +41 -0
  75. package/tooling/.automation/validation/history/2025-12-29_val_110771d7.json +32 -0
  76. package/tooling/.automation/validation/history/2025-12-29_val_13f3a7f9.json +32 -0
  77. package/tooling/.automation/validation/history/2025-12-29_val_17ba9d21.json +41 -0
  78. package/tooling/.automation/validation/history/2025-12-29_val_22247089.json +32 -0
  79. package/tooling/.automation/validation/history/2025-12-29_val_227ea6a4.json +32 -0
  80. package/tooling/.automation/validation/history/2025-12-29_val_2335d5ae.json +32 -0
  81. package/tooling/.automation/validation/history/2025-12-29_val_246824bb.json +41 -0
  82. package/tooling/.automation/validation/history/2025-12-29_val_28b4b9cd.json +32 -0
  83. package/tooling/.automation/validation/history/2025-12-29_val_2abd12cc.json +32 -0
  84. package/tooling/.automation/validation/history/2025-12-29_val_2c801b2f.json +59 -0
  85. package/tooling/.automation/validation/history/2025-12-29_val_2c8cfa8e.json +32 -0
  86. package/tooling/.automation/validation/history/2025-12-29_val_2ce76eb0.json +32 -0
  87. package/tooling/.automation/validation/history/2025-12-29_val_30351948.json +41 -0
  88. package/tooling/.automation/validation/history/2025-12-29_val_30eb7229.json +41 -0
  89. package/tooling/.automation/validation/history/2025-12-29_val_34df0e77.json +41 -0
  90. package/tooling/.automation/validation/history/2025-12-29_val_376e4d6a.json +32 -0
  91. package/tooling/.automation/validation/history/2025-12-29_val_3a4e8a1a.json +59 -0
  92. package/tooling/.automation/validation/history/2025-12-29_val_3b77a628.json +32 -0
  93. package/tooling/.automation/validation/history/2025-12-29_val_3ea4e1cf.json +59 -0
  94. package/tooling/.automation/validation/history/2025-12-29_val_44aacdb4.json +59 -0
  95. package/tooling/.automation/validation/history/2025-12-29_val_457ddfa8.json +32 -0
  96. package/tooling/.automation/validation/history/2025-12-29_val_45af6238.json +41 -0
  97. package/tooling/.automation/validation/history/2025-12-29_val_4735dba1.json +41 -0
  98. package/tooling/.automation/validation/history/2025-12-29_val_486b203c.json +41 -0
  99. package/tooling/.automation/validation/history/2025-12-29_val_49dc56cd.json +59 -0
  100. package/tooling/.automation/validation/history/2025-12-29_val_4d863d6d.json +32 -0
  101. package/tooling/.automation/validation/history/2025-12-29_val_5149a808.json +59 -0
  102. package/tooling/.automation/validation/history/2025-12-29_val_52e0bb43.json +32 -0
  103. package/tooling/.automation/validation/history/2025-12-29_val_585d6319.json +59 -0
  104. package/tooling/.automation/validation/history/2025-12-29_val_5b2d859a.json +32 -0
  105. package/tooling/.automation/validation/history/2025-12-29_val_635a7081.json +41 -0
  106. package/tooling/.automation/validation/history/2025-12-29_val_64df4905.json +32 -0
  107. package/tooling/.automation/validation/history/2025-12-29_val_70634cee.json +41 -0
  108. package/tooling/.automation/validation/history/2025-12-29_val_714553f9.json +32 -0
  109. package/tooling/.automation/validation/history/2025-12-29_val_7f7bfdbf.json +41 -0
  110. package/tooling/.automation/validation/history/2025-12-29_val_7faad91d.json +32 -0
  111. package/tooling/.automation/validation/history/2025-12-29_val_81821f8f.json +41 -0
  112. package/tooling/.automation/validation/history/2025-12-29_val_8249f3c9.json +32 -0
  113. package/tooling/.automation/validation/history/2025-12-29_val_8422b50f.json +41 -0
  114. package/tooling/.automation/validation/history/2025-12-29_val_8446c134.json +32 -0
  115. package/tooling/.automation/validation/history/2025-12-29_val_879f4e26.json +59 -0
  116. package/tooling/.automation/validation/history/2025-12-29_val_8b6d5bd7.json +32 -0
  117. package/tooling/.automation/validation/history/2025-12-29_val_8c5cd787.json +32 -0
  118. package/tooling/.automation/validation/history/2025-12-29_val_91d20bc7.json +32 -0
  119. package/tooling/.automation/validation/history/2025-12-29_val_958a12b7.json +41 -0
  120. package/tooling/.automation/validation/history/2025-12-29_val_95d91108.json +41 -0
  121. package/tooling/.automation/validation/history/2025-12-29_val_980dbb74.json +32 -0
  122. package/tooling/.automation/validation/history/2025-12-29_val_9e40c79b.json +32 -0
  123. package/tooling/.automation/validation/history/2025-12-29_val_9f499b7c.json +32 -0
  124. package/tooling/.automation/validation/history/2025-12-29_val_9f7c3b57.json +32 -0
  125. package/tooling/.automation/validation/history/2025-12-29_val_a30d5bd4.json +32 -0
  126. package/tooling/.automation/validation/history/2025-12-29_val_a6eb09c7.json +32 -0
  127. package/tooling/.automation/validation/history/2025-12-29_val_a86f7b83.json +41 -0
  128. package/tooling/.automation/validation/history/2025-12-29_val_ad5347e1.json +41 -0
  129. package/tooling/.automation/validation/history/2025-12-29_val_b0a5a993.json +32 -0
  130. package/tooling/.automation/validation/history/2025-12-29_val_bcb0192e.json +32 -0
  131. package/tooling/.automation/validation/history/2025-12-29_val_bf3c9aaa.json +32 -0
  132. package/tooling/.automation/validation/history/2025-12-29_val_c461ff88.json +32 -0
  133. package/tooling/.automation/validation/history/2025-12-29_val_c4f4e258.json +41 -0
  134. package/tooling/.automation/validation/history/2025-12-29_val_c7f0fa6d.json +41 -0
  135. package/tooling/.automation/validation/history/2025-12-29_val_c911b0e6.json +32 -0
  136. package/tooling/.automation/validation/history/2025-12-29_val_cc581964.json +32 -0
  137. package/tooling/.automation/validation/history/2025-12-29_val_cdd5a33b.json +32 -0
  138. package/tooling/.automation/validation/history/2025-12-29_val_cfd42495.json +32 -0
  139. package/tooling/.automation/validation/history/2025-12-29_val_d1c7a4ee.json +41 -0
  140. package/tooling/.automation/validation/history/2025-12-29_val_d2280d0e.json +32 -0
  141. package/tooling/.automation/validation/history/2025-12-29_val_d2a6ff69.json +32 -0
  142. package/tooling/.automation/validation/history/2025-12-29_val_d8c53ab2.json +59 -0
  143. package/tooling/.automation/validation/history/2025-12-29_val_d9c1247a.json +41 -0
  144. package/tooling/.automation/validation/history/2025-12-29_val_d9d58569.json +32 -0
  145. package/tooling/.automation/validation/history/2025-12-29_val_dabb4fd9.json +32 -0
  146. package/tooling/.automation/validation/history/2025-12-29_val_dd8fe359.json +32 -0
  147. package/tooling/.automation/validation/history/2025-12-29_val_decdffc9.json +32 -0
  148. package/tooling/.automation/validation/history/2025-12-29_val_e3a95476.json +59 -0
  149. package/tooling/.automation/validation/history/2025-12-29_val_e776dfca.json +32 -0
  150. package/tooling/.automation/validation/history/2025-12-29_val_ea70969f.json +59 -0
  151. package/tooling/.automation/validation/history/2025-12-29_val_ef41ea95.json +32 -0
  152. package/tooling/.automation/validation/history/2025-12-29_val_f384f9b1.json +32 -0
  153. package/tooling/.automation/validation/history/2025-12-29_val_f8adc38c.json +41 -0
  154. package/tooling/.automation/validation/history/2025-12-29_val_fa40b69e.json +32 -0
  155. package/tooling/.automation/validation/history/2025-12-29_val_fc538d54.json +41 -0
  156. package/tooling/.automation/validation/history/2025-12-29_val_fe814665.json +32 -0
  157. package/tooling/.automation/validation/history/2025-12-29_val_ffea4b12.json +32 -0
  158. package/tooling/.automation/validation/history/2025-12-30_val_02d001e5.json +59 -0
  159. package/tooling/.automation/validation/history/2025-12-30_val_0b8966dc.json +32 -0
  160. package/tooling/.automation/validation/history/2025-12-30_val_15455fbf.json +59 -0
  161. package/tooling/.automation/validation/history/2025-12-30_val_157e34b9.json +32 -0
  162. package/tooling/.automation/validation/history/2025-12-30_val_28d1d933.json +32 -0
  163. package/tooling/.automation/validation/history/2025-12-30_val_3442a52c.json +32 -0
  164. package/tooling/.automation/validation/history/2025-12-30_val_37f1ce1e.json +32 -0
  165. package/tooling/.automation/validation/history/2025-12-30_val_4f1d8a93.json +32 -0
  166. package/tooling/.automation/validation/history/2025-12-30_val_56ff1de3.json +32 -0
  167. package/tooling/.automation/validation/history/2025-12-30_val_664fd4e2.json +41 -0
  168. package/tooling/.automation/validation/history/2025-12-30_val_66afb0a7.json +32 -0
  169. package/tooling/.automation/validation/history/2025-12-30_val_7634663c.json +41 -0
  170. package/tooling/.automation/validation/history/2025-12-30_val_8ea830c3.json +41 -0
  171. package/tooling/.automation/validation/history/2025-12-30_val_998957c2.json +32 -0
  172. package/tooling/.automation/validation/history/2025-12-30_val_a52177db.json +32 -0
  173. package/tooling/.automation/validation/history/2025-12-30_val_a5b65a63.json +32 -0
  174. package/tooling/.automation/validation/history/2025-12-30_val_ae391d0e.json +32 -0
  175. package/tooling/.automation/validation/history/2025-12-30_val_c7895339.json +41 -0
  176. package/tooling/.automation/validation/history/2025-12-30_val_ca416593.json +41 -0
  177. package/tooling/.automation/validation/history/2025-12-30_val_cee19422.json +32 -0
  178. package/tooling/.automation/validation/history/2025-12-30_val_ddd4f4e6.json +32 -0
  179. package/tooling/.automation/validation/history/2025-12-30_val_f2e1394b.json +32 -0
  180. package/tooling/.automation/validation/history/2025-12-30_val_f4a7fa06.json +41 -0
  181. package/tooling/.automation/validation/history/2025-12-30_val_ffea3369.json +32 -0
  182. package/tooling/.automation/validation-config.yaml +103 -0
  183. package/tooling/completions/DevflowCompletion.ps1 +21 -21
  184. package/tooling/completions/_run-story +3 -3
  185. package/tooling/completions/run-story-completion.bash +8 -8
  186. package/tooling/docs/DOC-STANDARD.md +14 -14
  187. package/tooling/docs/templates/migration-spec.md +4 -4
  188. package/tooling/scripts/context_checkpoint.py +5 -15
  189. package/tooling/scripts/cost_dashboard.py +610 -13
  190. package/tooling/scripts/create-persona.py +1 -12
  191. package/tooling/scripts/create-persona.sh +44 -44
  192. package/tooling/scripts/lib/__init__.py +12 -1
  193. package/tooling/scripts/lib/agent_handoff.py +11 -2
  194. package/tooling/scripts/lib/agent_router.py +31 -10
  195. package/tooling/scripts/lib/colors.py +106 -0
  196. package/tooling/scripts/lib/context_monitor.py +766 -0
  197. package/tooling/scripts/lib/cost_config.py +229 -10
  198. package/tooling/scripts/lib/cost_display.py +20 -45
  199. package/tooling/scripts/lib/cost_tracker.py +462 -15
  200. package/tooling/scripts/lib/currency_converter.py +28 -5
  201. package/tooling/scripts/lib/pair_programming.py +102 -3
  202. package/tooling/scripts/lib/personality_system.py +949 -0
  203. package/tooling/scripts/lib/platform.py +55 -0
  204. package/tooling/scripts/lib/shared_memory.py +9 -3
  205. package/tooling/scripts/lib/swarm_orchestrator.py +514 -75
  206. package/tooling/scripts/lib/validation_loop.py +1014 -0
  207. package/tooling/scripts/memory_summarize.py +9 -2
  208. package/tooling/scripts/new-doc.py +2 -9
  209. package/tooling/scripts/personalize_agent.py +1 -12
  210. package/tooling/scripts/rollback-migration.sh +60 -60
  211. package/tooling/scripts/run-collab.ps1 +16 -16
  212. package/tooling/scripts/run-collab.py +88 -53
  213. package/tooling/scripts/run-collab.sh +4 -4
  214. package/tooling/scripts/run-story.py +278 -20
  215. package/tooling/scripts/run-story.sh +3 -3
  216. package/tooling/scripts/setup-checkpoint-service.py +2 -9
  217. package/tooling/scripts/tech-debt-tracker.py +1 -12
  218. package/tooling/scripts/test_adversarial_swarm.py +452 -0
  219. package/tooling/scripts/update_version.py +48 -2
  220. package/tooling/scripts/validate-overrides.py +1 -10
  221. package/tooling/scripts/validate-overrides.sh +40 -40
  222. package/tooling/scripts/validate_loop.py +162 -0
  223. package/tooling/scripts/validate_setup.py +2 -30
  224. package/.claude/skills/init/SKILL.md +0 -496
  225. package/bin/devflow-init.js +0 -10
  226. package/tooling/scripts/init-project-workflow.ps1 +0 -651
  227. package/tooling/scripts/init-project-workflow.py +0 -70
  228. package/tooling/scripts/init-project-workflow.sh +0 -746
@@ -0,0 +1,272 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Session Tracker - Tracks costs for ALL Claude Code sessions.
4
+
5
+ Called by hooks to track token usage across the entire session lifecycle.
6
+
7
+ Usage:
8
+ python session_tracker.py start [--session-id ID]
9
+ python session_tracker.py log --input TOKENS --output TOKENS [--model MODEL]
10
+ python session_tracker.py end
11
+ python session_tracker.py status
12
+ """
13
+
14
+ import argparse
15
+ import json
16
+ from datetime import datetime
17
+ from pathlib import Path
18
+
19
+ # Project paths
20
+ PROJECT_DIR = Path(__file__).parent.parent.parent
21
+ COSTS_DIR = PROJECT_DIR / "tooling" / ".automation" / "costs"
22
+ SESSIONS_DIR = COSTS_DIR / "sessions"
23
+ ACTIVE_SESSION_FILE = COSTS_DIR / ".active_session.json"
24
+
25
+ # Pricing per 1M tokens (USD) - December 2025
26
+ PRICING = {
27
+ "claude-opus-4-5-20251101": {"input": 15.00, "output": 75.00},
28
+ "claude-sonnet-4-20250514": {"input": 3.00, "output": 15.00},
29
+ "claude-3-5-sonnet-20241022": {"input": 3.00, "output": 15.00},
30
+ "claude-3-5-haiku-20241022": {"input": 0.80, "output": 4.00},
31
+ "claude-3-opus-20240229": {"input": 15.00, "output": 75.00},
32
+ "opus": {"input": 15.00, "output": 75.00},
33
+ "sonnet": {"input": 3.00, "output": 15.00},
34
+ "haiku": {"input": 0.80, "output": 4.00},
35
+ }
36
+
37
+
38
+ def get_pricing(model: str) -> dict:
39
+ """Get pricing for a model."""
40
+ model_lower = model.lower()
41
+
42
+ # Direct match
43
+ if model_lower in PRICING:
44
+ return PRICING[model_lower]
45
+
46
+ # Partial match
47
+ for key, price in PRICING.items():
48
+ if key in model_lower or model_lower in key:
49
+ return price
50
+
51
+ # Check for model family
52
+ if "opus" in model_lower:
53
+ return PRICING["opus"]
54
+ elif "sonnet" in model_lower:
55
+ return PRICING["sonnet"]
56
+ elif "haiku" in model_lower:
57
+ return PRICING["haiku"]
58
+
59
+ # Default to sonnet pricing
60
+ return PRICING["sonnet"]
61
+
62
+
63
+ def calculate_cost(input_tokens: int, output_tokens: int, model: str) -> float:
64
+ """Calculate cost in USD."""
65
+ pricing = get_pricing(model)
66
+ input_cost = (input_tokens / 1_000_000) * pricing["input"]
67
+ output_cost = (output_tokens / 1_000_000) * pricing["output"]
68
+ return input_cost + output_cost
69
+
70
+
71
+ def ensure_dirs():
72
+ """Ensure required directories exist."""
73
+ COSTS_DIR.mkdir(parents=True, exist_ok=True)
74
+ SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
75
+
76
+
77
+ def start_session(session_id: str = None, model: str = None) -> dict:
78
+ """Start a new tracking session."""
79
+ ensure_dirs()
80
+
81
+ now = datetime.now()
82
+ if not session_id:
83
+ session_id = now.strftime("%Y%m%d_%H%M%S")
84
+
85
+ session = {
86
+ "session_id": session_id,
87
+ "start_time": now.isoformat(),
88
+ "end_time": None,
89
+ "model": model or "unknown",
90
+ "story_key": None,
91
+ "entries": [],
92
+ "totals": {
93
+ "input_tokens": 0,
94
+ "output_tokens": 0,
95
+ "total_tokens": 0,
96
+ "cost_usd": 0.0,
97
+ },
98
+ }
99
+
100
+ # Save active session
101
+ with open(ACTIVE_SESSION_FILE, "w") as f:
102
+ json.dump(session, f, indent=2)
103
+
104
+ return session
105
+
106
+
107
+ def get_active_session() -> dict | None:
108
+ """Get the currently active session."""
109
+ if not ACTIVE_SESSION_FILE.exists():
110
+ return None
111
+
112
+ try:
113
+ with open(ACTIVE_SESSION_FILE) as f:
114
+ return json.load(f)
115
+ except (OSError, json.JSONDecodeError):
116
+ return None
117
+
118
+
119
+ def log_usage(input_tokens: int, output_tokens: int, model: str = None) -> dict | None:
120
+ """Log token usage to the active session."""
121
+ session = get_active_session()
122
+
123
+ if not session:
124
+ # Auto-start session if none exists
125
+ session = start_session(model=model)
126
+
127
+ # Update model if provided
128
+ if model and session.get("model") == "unknown":
129
+ session["model"] = model
130
+
131
+ # Use session model for pricing
132
+ use_model = model or session.get("model", "sonnet")
133
+ cost = calculate_cost(input_tokens, output_tokens, use_model)
134
+
135
+ # Create entry
136
+ entry = {
137
+ "timestamp": datetime.now().isoformat(),
138
+ "model": use_model,
139
+ "input_tokens": input_tokens,
140
+ "output_tokens": output_tokens,
141
+ "cost_usd": cost,
142
+ }
143
+
144
+ session["entries"].append(entry)
145
+
146
+ # Update totals
147
+ session["totals"]["input_tokens"] += input_tokens
148
+ session["totals"]["output_tokens"] += output_tokens
149
+ session["totals"]["total_tokens"] += input_tokens + output_tokens
150
+ session["totals"]["cost_usd"] += cost
151
+
152
+ # Save updated session
153
+ with open(ACTIVE_SESSION_FILE, "w") as f:
154
+ json.dump(session, f, indent=2)
155
+
156
+ return session
157
+
158
+
159
+ def end_session() -> dict | None:
160
+ """End the current session and save to sessions directory."""
161
+ session = get_active_session()
162
+
163
+ if not session:
164
+ return None
165
+
166
+ # Set end time
167
+ session["end_time"] = datetime.now().isoformat()
168
+
169
+ # Only save if there was activity
170
+ if session["totals"]["total_tokens"] > 0:
171
+ # Generate filename
172
+ start_time = datetime.fromisoformat(session["start_time"])
173
+ filename = f"{start_time.strftime('%Y-%m-%d')}_{session['session_id']}.json"
174
+ session_file = SESSIONS_DIR / filename
175
+
176
+ # Save to sessions directory
177
+ with open(session_file, "w") as f:
178
+ json.dump(session, f, indent=2)
179
+
180
+ # Remove active session file
181
+ if ACTIVE_SESSION_FILE.exists():
182
+ ACTIVE_SESSION_FILE.unlink()
183
+
184
+ return session
185
+
186
+
187
+ def get_status() -> dict:
188
+ """Get current session status."""
189
+ session = get_active_session()
190
+
191
+ if not session:
192
+ return {"active": False, "message": "No active session"}
193
+
194
+ totals = session.get("totals", {})
195
+ return {
196
+ "active": True,
197
+ "session_id": session.get("session_id"),
198
+ "model": session.get("model"),
199
+ "input_tokens": totals.get("input_tokens", 0),
200
+ "output_tokens": totals.get("output_tokens", 0),
201
+ "total_tokens": totals.get("total_tokens", 0),
202
+ "cost_usd": totals.get("cost_usd", 0.0),
203
+ "entries_count": len(session.get("entries", [])),
204
+ }
205
+
206
+
207
+ def main():
208
+ parser = argparse.ArgumentParser(description="Session cost tracker")
209
+ subparsers = parser.add_subparsers(dest="command", required=True)
210
+
211
+ # Start command
212
+ start_parser = subparsers.add_parser("start", help="Start a new session")
213
+ start_parser.add_argument("--session-id", help="Custom session ID")
214
+ start_parser.add_argument("--model", help="Model name")
215
+
216
+ # Log command
217
+ log_parser = subparsers.add_parser("log", help="Log token usage")
218
+ log_parser.add_argument("--input", type=int, required=True, help="Input tokens")
219
+ log_parser.add_argument("--output", type=int, required=True, help="Output tokens")
220
+ log_parser.add_argument("--model", help="Model name")
221
+
222
+ # End command
223
+ subparsers.add_parser("end", help="End current session")
224
+
225
+ # Status command
226
+ subparsers.add_parser("status", help="Get session status")
227
+
228
+ args = parser.parse_args()
229
+
230
+ if args.command == "start":
231
+ session = start_session(args.session_id, args.model)
232
+ print(json.dumps({"status": "started", "session_id": session["session_id"]}))
233
+
234
+ elif args.command == "log":
235
+ model = getattr(args, "model", None)
236
+ session = log_usage(args.input, args.output, model)
237
+ if session:
238
+ print(
239
+ json.dumps(
240
+ {
241
+ "status": "logged",
242
+ "total_tokens": session["totals"]["total_tokens"],
243
+ "cost_usd": round(session["totals"]["cost_usd"], 4),
244
+ }
245
+ )
246
+ )
247
+ else:
248
+ print(json.dumps({"status": "error", "message": "No active session"}))
249
+
250
+ elif args.command == "end":
251
+ session = end_session()
252
+ if session:
253
+ print(
254
+ json.dumps(
255
+ {
256
+ "status": "ended",
257
+ "total_tokens": session["totals"]["total_tokens"],
258
+ "cost_usd": round(session["totals"]["cost_usd"], 4),
259
+ "saved": session["totals"]["total_tokens"] > 0,
260
+ }
261
+ )
262
+ )
263
+ else:
264
+ print(json.dumps({"status": "no_session"}))
265
+
266
+ elif args.command == "status":
267
+ status = get_status()
268
+ print(json.dumps(status))
269
+
270
+
271
+ if __name__ == "__main__":
272
+ main()
@@ -0,0 +1,38 @@
1
+ {
2
+ "statusLine": {
3
+ "type": "command",
4
+ "command": "~/.claude/statusline.sh"
5
+ },
6
+ "hooks": {
7
+ "SessionStart": [
8
+ {
9
+ "hooks": [
10
+ {
11
+ "type": "command",
12
+ "command": ".claude/hooks/session-startup.sh"
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "Stop": [
18
+ {
19
+ "hooks": [
20
+ {
21
+ "type": "command",
22
+ "command": ".claude/hooks/session-stop.sh"
23
+ }
24
+ ]
25
+ }
26
+ ],
27
+ "Notification": [
28
+ {
29
+ "hooks": [
30
+ {
31
+ "type": "command",
32
+ "command": ".claude/hooks/session-notification.sh"
33
+ }
34
+ ]
35
+ }
36
+ ]
37
+ }
38
+ }
@@ -0,0 +1,156 @@
1
+ ---
2
+ name: costs
3
+ description: View cost dashboard and spending analytics (project)
4
+ ---
5
+
6
+ # Cost Dashboard Skill
7
+
8
+ Display Devflow cost tracking and spending analytics by reading session data directly.
9
+
10
+ ## Usage
11
+
12
+ ```
13
+ /costs [options]
14
+ ```
15
+
16
+ ## Options
17
+
18
+ | Option | Description |
19
+ |--------|-------------|
20
+ | --period day | Show today's costs only |
21
+ | --period week | Show this week's costs |
22
+ | --period month | Show this month's costs (default) |
23
+ | --history N | Show last N sessions |
24
+ | --story KEY | Filter by story key |
25
+
26
+ ## Prompt
27
+
28
+ You are displaying the Devflow cost dashboard.
29
+
30
+ **Arguments:** $ARGUMENTS
31
+
32
+ ### Step 1: Read Configuration
33
+
34
+ Read the configuration file:
35
+ - Path: `tooling/.automation/costs/config.json`
36
+
37
+ This contains:
38
+ - `budget_dev`: Development budget (USD)
39
+ - `subscription_plan`: Current plan (free/pro)
40
+ - `subscription_token_limit`: Monthly token limit
41
+ - `subscription_billing_period_days`: Days in billing period
42
+ - `display_currencies`: Currencies to show
43
+ - `currency_rates`: Exchange rates
44
+
45
+ ### Step 2: Find Session Files
46
+
47
+ Find all session files:
48
+ - Path pattern: `tooling/.automation/costs/sessions/*.json`
49
+
50
+ ### Step 3: Read and Aggregate Session Data
51
+
52
+ For each session file, extract:
53
+ - `session_id`: Session identifier
54
+ - `start_time` / `end_time`: Timestamps
55
+ - `story_key`: Associated story (if any)
56
+ - `entries[]`: Array of cost entries with `model`, `input_tokens`, `output_tokens`, `cost_usd`
57
+ - `totals`: Aggregated totals for the session
58
+
59
+ Identify the most recent session as the "current session".
60
+
61
+ ### Step 4: Calculate Metrics
62
+
63
+ Calculate:
64
+ 1. **Current session tokens/cost**: From the most recent session
65
+ 2. **Cumulative tokens**: Sum of all tokens across ALL sessions this billing period
66
+ 3. **Cumulative cost**: Sum of all `cost_usd` across ALL sessions
67
+ 4. **Cost by model**: Group costs by model (opus, sonnet, haiku)
68
+ 5. **Cost by story**: Group costs by story_key
69
+ 6. **Budget usage**: (cumulative_cost / budget_dev) * 100
70
+ 7. **Subscription usage**: (cumulative_tokens / subscription_token_limit) * 100
71
+ 8. **Average cost per session**: cumulative_cost / session_count
72
+ 9. **Average tokens per session**: cumulative_tokens / session_count
73
+ 10. **Input/output ratio**: total_input_tokens / total_output_tokens
74
+ 11. **Days remaining**: Calculate from billing period start
75
+ 12. **Projected monthly cost**: (cumulative_cost / days_elapsed) * 30
76
+ 13. **Projected token usage**: (cumulative_tokens / days_elapsed) * 30
77
+
78
+ ### Step 5: Apply Filters
79
+
80
+ Based on $ARGUMENTS:
81
+ - `--period day`: Filter sessions from today only
82
+ - `--period week`: Filter sessions from last 7 days
83
+ - `--period month`: Filter sessions from last 30 days (default)
84
+ - `--history N`: Show only last N sessions
85
+ - `--story KEY`: Filter sessions matching story_key
86
+
87
+ ### Step 6: Format Output
88
+
89
+ Display the dashboard using this format:
90
+
91
+ ```
92
+ =================================================================
93
+ DEVFLOW COST DASHBOARD
94
+ =================================================================
95
+ Plan: [plan] | Tokens: [cumulative]/[limit] ([%]%) | [days] days left
96
+ This Session: $[current_cost] | Cumulative: $[total_cost]
97
+ =================================================================
98
+
99
+ PERIOD: [period] SESSIONS: [count]
100
+
101
+ --- TOKEN USAGE ---------------------------------------------
102
+ This Session Cumulative
103
+ Input: [current_in] [total_in]
104
+ Output: [current_out] [total_out]
105
+ Total: [current_total] [total_total]
106
+
107
+ I/O Ratio: [ratio]:1 (higher = more input-heavy conversations)
108
+
109
+ --- COST BY MODEL -------------------------------------------
110
+ [model] $[cost] ([%]%) [bar]
111
+
112
+ --- COST BY STORY -------------------------------------------
113
+ [story-key] $[cost] ([%]%)
114
+ (no story) $[cost] ([%]%)
115
+
116
+ --- BUDGET STATUS -------------------------------------------
117
+ Spent: $[total] / $[budget] ([%]%)
118
+ [================================--------------------] [%]%
119
+
120
+ [WARNING] if > 75%: "Approaching budget limit!"
121
+ [CRITICAL] if > 90%: "Near budget limit - consider pausing"
122
+
123
+ --- PROJECTIONS (based on current usage rate) ---------------
124
+ Monthly token projection: [projected] / [limit] ([%]%)
125
+ Monthly cost projection: $[projected_cost]
126
+ Avg cost per session: $[avg_cost]
127
+ Avg tokens per session: [avg_tokens]
128
+
129
+ --- RECENT SESSIONS -----------------------------------------
130
+ [session_id] [date] [tokens] $[cost] [story or "-"]
131
+ [session_id] [date] [tokens] $[cost] [story or "-"]
132
+ [session_id] [date] [tokens] $[cost] [story or "-"]
133
+ (show last 5 sessions)
134
+
135
+ --- CURRENCIES ----------------------------------------------
136
+ $[USD] | E[EUR] | L[GBP] | R$[BRL]
137
+ =================================================================
138
+ ```
139
+
140
+ ### Budget Warnings
141
+
142
+ Display warnings based on config thresholds:
143
+ - If budget usage > `warning_percent` (75%): Show [WARNING]
144
+ - If budget usage > `critical_percent` (90%): Show [CRITICAL]
145
+ - If subscription usage > 80%: Show token limit warning
146
+
147
+ ### Notes
148
+
149
+ - Format large numbers with K/M suffixes (e.g., 1.5K, 2.3M)
150
+ - Round costs to 2 decimal places
151
+ - Show percentages to 1 decimal place
152
+ - Use text-based progress bars with = and - characters
153
+ - Current session = most recent session file by timestamp
154
+ - Cumulative = sum of ALL sessions in the billing period
155
+ - If no sessions found, display a message indicating no cost data available
156
+ - Calculate days remaining: billing_period_days - days since first session of period
@@ -0,0 +1,101 @@
1
+ # Validate Skill
2
+
3
+ Run automated validation checks with feedback loops.
4
+
5
+ ## Description
6
+
7
+ The validate skill runs a three-tier validation system:
8
+
9
+ 1. **Pre-flight** (Tier 1): Checks before execution
10
+ - Story file exists
11
+ - Budget is available
12
+ - Dependencies are valid
13
+
14
+ 2. **Inter-phase** (Tier 2): Checks between agents
15
+ - Code compiles/parses
16
+ - Linting passes
17
+ - Phase transitions are valid
18
+
19
+ 3. **Post-completion** (Tier 3): Checks after pipeline
20
+ - Tests pass
21
+ - Types are valid
22
+ - Version is synced
23
+ - Changelog is updated
24
+
25
+ ## Usage
26
+
27
+ ```
28
+ /validate [story-key] [--tier 1|2|3|all] [--auto-fix] [--json]
29
+ ```
30
+
31
+ ## Arguments
32
+
33
+ | Argument | Description | Default |
34
+ |----------|-------------|---------|
35
+ | story-key | Story identifier to validate | Current branch |
36
+ | --tier | Validation tier (1, 2, 3, or all) | all |
37
+ | --auto-fix | Attempt automatic fixes | false |
38
+ | --json | Output as JSON | false |
39
+ | --quiet | Minimal output | false |
40
+
41
+ ## Examples
42
+
43
+ ### Run all validations
44
+ ```
45
+ /validate 3-5 --tier all
46
+ ```
47
+
48
+ ### Run post-completion checks with auto-fix
49
+ ```
50
+ /validate --tier 3 --auto-fix
51
+ ```
52
+
53
+ ### Get JSON output for CI
54
+ ```
55
+ /validate 3-5 --json
56
+ ```
57
+
58
+ ## Prompt
59
+
60
+ You are running validation checks for the Devflow project.
61
+
62
+ $ARGUMENTS
63
+
64
+ Execute the validation loop:
65
+
66
+ ```python
67
+ import sys
68
+ sys.path.insert(0, "tooling/scripts/lib")
69
+
70
+ from validation_loop import (
71
+ create_validation_loop,
72
+ run_preflight_validation,
73
+ run_post_completion_validation,
74
+ ALL_GATES,
75
+ LoopContext,
76
+ )
77
+
78
+ # Parse arguments
79
+ story_key = "$ARGUMENTS".split()[0] if "$ARGUMENTS" else "validation-check"
80
+ tier = "all" # Default to all tiers
81
+
82
+ # Create context
83
+ context = LoopContext(story_key=story_key)
84
+
85
+ # Run appropriate validation
86
+ if tier == "1" or tier == "all":
87
+ print("[VALIDATION] Running pre-flight checks...")
88
+ report = run_preflight_validation(story_key)
89
+ print(report.to_summary())
90
+
91
+ if tier == "3" or tier == "all":
92
+ print("[VALIDATION] Running post-completion checks...")
93
+ report = run_post_completion_validation(story_key)
94
+ print(report.to_summary())
95
+ ```
96
+
97
+ Report results clearly with:
98
+ - [PASS] for passed gates
99
+ - [WARN] for warnings
100
+ - [FAIL] for failures
101
+ - Suggested fixes when available