@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
@@ -28,7 +28,7 @@ Examples:
28
28
  import argparse
29
29
  import json
30
30
  import os
31
- import platform
31
+ import platform as platform_stdlib
32
32
  import shutil
33
33
  import sys
34
34
  from datetime import datetime
@@ -38,10 +38,9 @@ from typing import Optional
38
38
  SCRIPT_DIR = Path(__file__).parent
39
39
  sys.path.insert(0, str(SCRIPT_DIR / "lib"))
40
40
 
41
- # Cross-platform detection
42
- IS_WINDOWS = platform.system() == "Windows"
43
- IS_MACOS = platform.system() == "Darwin"
44
- IS_LINUX = platform.system() == "Linux"
41
+ from platform import IS_MACOS, IS_WINDOWS
42
+
43
+ from colors import Colors
45
44
 
46
45
 
47
46
  def detect_claude_cli() -> Optional[str]:
@@ -63,8 +62,8 @@ def detect_claude_cli() -> Optional[str]:
63
62
  if IS_WINDOWS:
64
63
  # Check common Windows install locations
65
64
  possible_paths = [
66
- Path(os.environ.get("LOCALAPPDATA", "")) / "Programs" / "claude" / "claude.exe",
67
- Path(os.environ.get("PROGRAMFILES", "")) / "Claude" / "claude.exe",
65
+ Path(os.getenv("LOCALAPPDATA", "")) / "Programs" / "claude" / "claude.exe",
66
+ Path(os.getenv("PROGRAMFILES", "")) / "Claude" / "claude.exe",
68
67
  Path.home() / ".claude" / "local" / "claude.exe",
69
68
  Path.home() / "AppData" / "Local" / "Programs" / "claude" / "claude.exe",
70
69
  ]
@@ -130,13 +129,13 @@ def get_config_dir() -> Path:
130
129
  Path to configuration directory.
131
130
  """
132
131
  if IS_WINDOWS:
133
- base = Path(os.environ.get("APPDATA", Path.home() / "AppData" / "Roaming"))
132
+ base = Path(os.getenv("APPDATA") or str(Path.home() / "AppData" / "Roaming"))
134
133
  return base / "devflow"
135
134
  elif IS_MACOS:
136
135
  return Path.home() / "Library" / "Application Support" / "devflow"
137
136
  else:
138
137
  # Linux/Unix: Use XDG
139
- xdg_data = os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")
138
+ xdg_data = os.getenv("XDG_DATA_HOME") or str(Path.home() / ".local" / "share")
140
139
  return Path(xdg_data) / "devflow"
141
140
 
142
141
 
@@ -147,12 +146,12 @@ def get_cache_dir() -> Path:
147
146
  Path to cache directory.
148
147
  """
149
148
  if IS_WINDOWS:
150
- base = Path(os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local"))
149
+ base = Path(os.getenv("LOCALAPPDATA") or str(Path.home() / "AppData" / "Local"))
151
150
  return base / "devflow" / "cache"
152
151
  elif IS_MACOS:
153
152
  return Path.home() / "Library" / "Caches" / "devflow"
154
153
  else:
155
- xdg_cache = os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache")
154
+ xdg_cache = os.getenv("XDG_CACHE_HOME") or str(Path.home() / ".cache")
156
155
  return Path(xdg_cache) / "devflow"
157
156
 
158
157
 
@@ -163,46 +162,18 @@ from lib.pair_programming import PairConfig, PairSession # noqa: E402
163
162
  from lib.shared_memory import get_knowledge_graph, get_shared_memory, share_learning # noqa: E402
164
163
  from lib.swarm_orchestrator import ConsensusType, SwarmConfig, SwarmOrchestrator # noqa: E402
165
164
 
166
-
167
- # Colors for terminal output (with Windows support)
168
- class Colors:
169
- """ANSI color codes with Windows compatibility."""
170
-
171
- # Enable ANSI colors on Windows
172
- if IS_WINDOWS:
173
- try:
174
- import ctypes
175
-
176
- kernel32 = ctypes.windll.kernel32
177
- kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
178
- except Exception:
179
- pass # Fall back to no colors
180
-
181
- # Check if colors should be enabled
182
- _use_colors = (
183
- sys.stdout.isatty()
184
- and os.environ.get("NO_COLOR") is None
185
- and os.environ.get("TERM") != "dumb"
165
+ # Try to import validation loop
166
+ try:
167
+ from lib.validation_loop import (
168
+ POST_COMPLETION_GATES,
169
+ PREFLIGHT_GATES,
170
+ LoopContext,
171
+ ValidationLoop,
186
172
  )
187
173
 
188
- if _use_colors:
189
- HEADER = "\033[95m"
190
- BLUE = "\033[94m"
191
- CYAN = "\033[96m"
192
- GREEN = "\033[92m"
193
- YELLOW = "\033[93m"
194
- RED = "\033[91m"
195
- BOLD = "\033[1m"
196
- END = "\033[0m"
197
- else:
198
- HEADER = ""
199
- BLUE = ""
200
- CYAN = ""
201
- GREEN = ""
202
- YELLOW = ""
203
- RED = ""
204
- BOLD = ""
205
- END = ""
174
+ HAS_VALIDATION = True
175
+ except ImportError:
176
+ HAS_VALIDATION = False
206
177
 
207
178
 
208
179
  def print_banner():
@@ -314,8 +285,8 @@ def run_sequential_mode(story_key: str, task: str, agents: list[str], args: argp
314
285
  # Get context including handoffs
315
286
  context = handoff_gen.generate_context_for_agent(agent)
316
287
 
317
- # Build prompt
318
- f"""You are the {agent} agent.
288
+ # Build prompt for agent invocation
289
+ prompt = f"""You are the {agent} agent.
319
290
 
320
291
  {context}
321
292
 
@@ -329,6 +300,8 @@ Complete your part of this task according to your role.
329
300
  """
330
301
 
331
302
  # Invoke agent (simplified - in real use would call Claude CLI)
303
+ # Note: prompt is prepared above for when full agent invocation is implemented
304
+ _ = prompt # Acknowledge prompt is ready for future use
332
305
  print(" -> Generating response...")
333
306
 
334
307
  # For demo, we'll note the handoff
@@ -379,7 +352,7 @@ def save_result(story_key: str, mode: str, result: dict):
379
352
  "story_key": story_key,
380
353
  "mode": mode,
381
354
  "timestamp": datetime.now().isoformat(),
382
- "platform": platform.system(),
355
+ "platform": platform_stdlib.system(),
383
356
  "result": result,
384
357
  },
385
358
  f,
@@ -497,9 +470,61 @@ Examples:
497
470
  parser.add_argument("--quiet", "-q", action="store_true", help="Reduce output verbosity")
498
471
  parser.add_argument("--task", type=str, help="Override task description")
499
472
 
473
+ # Validation options
474
+ parser.add_argument("--validate", action="store_true", help="Enable validation loop")
475
+ parser.add_argument("--no-validate", action="store_true", help="Disable validation loop")
476
+
500
477
  return parser.parse_args()
501
478
 
502
479
 
480
+ def run_validation(story_key: str, args: argparse.Namespace, tier: str = "preflight") -> bool:
481
+ """Run validation checks.
482
+
483
+ Args:
484
+ story_key: Story identifier
485
+ args: Command line arguments
486
+ tier: Which tier to run ("preflight" or "post")
487
+
488
+ Returns:
489
+ True if validation passed, False otherwise
490
+ """
491
+ if not HAS_VALIDATION:
492
+ return True
493
+
494
+ validation_enabled = args.validate and not args.no_validate
495
+ if not validation_enabled:
496
+ return True
497
+
498
+ gates = PREFLIGHT_GATES if tier == "preflight" else POST_COMPLETION_GATES
499
+ validation_loop = ValidationLoop(
500
+ gates=gates,
501
+ config={"auto_fix_enabled": True},
502
+ story_key=story_key,
503
+ )
504
+ context = LoopContext(story_key=story_key, phase=tier)
505
+
506
+ if tier == "preflight":
507
+ print(f"\n{Colors.CYAN}[VALIDATION] Running pre-flight checks...{Colors.END}")
508
+ report = validation_loop.run_preflight(context)
509
+ else:
510
+ print(f"\n{Colors.CYAN}[VALIDATION] Running post-completion checks...{Colors.END}")
511
+ report = validation_loop.run_post_completion(context)
512
+
513
+ if report.passed:
514
+ print(
515
+ f"{Colors.GREEN}[PASS] Validation passed ({len(report.gate_results)} gates){Colors.END}"
516
+ )
517
+ if report.warnings:
518
+ for warn in report.warnings:
519
+ print(f" {Colors.YELLOW}[WARN] {warn.gate_name}: {warn.message}{Colors.END}")
520
+ return True
521
+ else:
522
+ print(f"{Colors.RED}[FAIL] Validation failed{Colors.END}")
523
+ for failure in report.failures:
524
+ print(f" - {failure.gate_name}: {failure.message}")
525
+ return tier != "preflight" # Block on preflight, warn on post
526
+
527
+
503
528
  def main():
504
529
  args = parse_args()
505
530
 
@@ -532,6 +557,11 @@ def main():
532
557
  print(f"{Colors.BOLD}Story/Task:{Colors.END} {story_key}")
533
558
  print(f"{Colors.BOLD}Mode:{Colors.END} ", end="")
534
559
 
560
+ # Run pre-flight validation
561
+ if not run_validation(story_key, args, "preflight"):
562
+ print(f"\n{Colors.RED}[BLOCKED] Pre-flight validation failed. Aborting.{Colors.END}")
563
+ return 1
564
+
535
565
  # Route-only mode
536
566
  if args.route_only:
537
567
  print("Route Analysis Only")
@@ -579,12 +609,17 @@ def main():
579
609
  print("Sequential")
580
610
  if not agents:
581
611
  agents = ["SM", "DEV", "REVIEWER"]
582
- run_sequential_mode(story_key, task, agents, args)
612
+ results = run_sequential_mode(story_key, task, agents, args)
613
+ if results:
614
+ print(f" Completed {len(results)} agent(s)")
583
615
 
584
616
  else: # auto mode
585
617
  print("Auto-Route")
586
618
  run_auto_mode(story_key, task, args)
587
619
 
620
+ # Run post-completion validation
621
+ run_validation(story_key, args, "post")
622
+
588
623
  print(f"\n{Colors.GREEN}{'═' * 60}{Colors.END}")
589
624
  print(f"{Colors.GREEN} Collaboration complete!{Colors.END}")
590
625
  return 0
@@ -84,25 +84,25 @@ main() {
84
84
  show_usage
85
85
  exit 0
86
86
  fi
87
-
87
+
88
88
  # Check for Python
89
89
  PYTHON_CMD=$(detect_python)
90
90
  if [[ -z "$PYTHON_CMD" ]]; then
91
91
  echo -e "${RED}Error: Python 3 not found. Please install Python 3.9+${NC}"
92
92
  exit 1
93
93
  fi
94
-
94
+
95
95
  # Check if Python script exists
96
96
  if [[ ! -f "$PYTHON_SCRIPT" ]]; then
97
97
  echo -e "${RED}Error: run-collab.py not found at $PYTHON_SCRIPT${NC}"
98
98
  exit 1
99
99
  fi
100
-
100
+
101
101
  # Print banner for non-quiet mode
102
102
  if [[ "$*" != *"--quiet"* && "$*" != *"-q"* ]]; then
103
103
  print_banner
104
104
  fi
105
-
105
+
106
106
  # Pass all arguments to Python script
107
107
  exec "$PYTHON_CMD" "$PYTHON_SCRIPT" "$@"
108
108
  }
@@ -39,15 +39,32 @@ SCRIPT_DIR = Path(__file__).parent
39
39
  # Add lib directory for imports
40
40
  sys.path.insert(0, str(SCRIPT_DIR / "lib"))
41
41
 
42
+ from platform import IS_WINDOWS, get_platform
43
+
44
+ from colors import Colors
45
+
46
+ # Try to import context monitor
47
+ try:
48
+ from context_monitor import ContextMonitor, StatusLine, get_status_manager
49
+
50
+ HAS_CONTEXT_MONITOR = True
51
+ except ImportError:
52
+ HAS_CONTEXT_MONITOR = False
53
+
54
+ # Try to import validation loop
55
+ try:
56
+ from validation_loop import (
57
+ INTER_PHASE_GATES,
58
+ POST_COMPLETION_GATES,
59
+ PREFLIGHT_GATES,
60
+ LoopContext,
61
+ ValidationLoop,
62
+ get_phase_gates,
63
+ )
42
64
 
43
- def get_platform():
44
- """Detect the current platform."""
45
- if sys.platform == "win32":
46
- return "windows"
47
- elif sys.platform == "darwin":
48
- return "macos"
49
- else:
50
- return "linux"
65
+ HAS_VALIDATION = True
66
+ except ImportError:
67
+ HAS_VALIDATION = False
51
68
 
52
69
 
53
70
  def run_windows(args):
@@ -121,19 +138,35 @@ Examples:
121
138
  "--native", action="store_true", help="Run natively with Python (enables cost tracking)"
122
139
  )
123
140
  parser.add_argument("--no-monitor", action="store_true", help="Disable live monitoring display")
141
+ parser.add_argument(
142
+ "--validate",
143
+ action="store_true",
144
+ help="Enable validation loop (pre-flight, inter-phase, post-completion)",
145
+ )
146
+ parser.add_argument("--no-validate", action="store_true", help="Disable validation loop")
147
+ parser.add_argument(
148
+ "--validation-tier",
149
+ type=int,
150
+ choices=[1, 2, 3],
151
+ help="Run specific validation tier only (1=preflight, 2=inter-phase, 3=post-completion)",
152
+ )
124
153
 
125
154
  return parser.parse_args()
126
155
 
127
156
 
128
157
  class NativeRunner:
129
- """Native Python runner with cost tracking."""
158
+ """Native Python runner with cost tracking, context monitoring, and validation."""
130
159
 
131
160
  def __init__(self, args):
132
161
  self.args = args
133
162
  self.tracker = None
134
163
  self.display = None
164
+ self.context_monitor = None
165
+ self.status_line = None
135
166
  self.monitor_thread = None
136
167
  self.running = False
168
+ self.validation_loop = None
169
+ self.validation_context = None
137
170
 
138
171
  # Import cost modules
139
172
  try:
@@ -148,8 +181,145 @@ class NativeRunner:
148
181
  print(f"Warning: Cost tracking not available: {e}")
149
182
  self.cost_available = False
150
183
 
184
+ # Initialize context monitor if available
185
+ if HAS_CONTEXT_MONITOR:
186
+ self.context_monitor = ContextMonitor(
187
+ story_key=args.story_key,
188
+ model=args.model,
189
+ on_threshold=self._on_context_threshold,
190
+ )
191
+ else:
192
+ self.context_monitor = None
193
+
194
+ # Initialize validation if available and enabled
195
+ self.validation_enabled = (
196
+ HAS_VALIDATION and (args.validate or not args.no_validate) and not args.no_validate
197
+ )
198
+ if self.validation_enabled:
199
+ self._init_validation()
200
+
201
+ def _on_context_threshold(self, level, state):
202
+ """Handle context threshold crossing."""
203
+ from context_monitor import ContextLevel
204
+
205
+ if level == ContextLevel.EMERGENCY:
206
+ print(f"\n{Colors.BG_RED}{Colors.WHITE} CONTEXT EMERGENCY {Colors.RESET}")
207
+ print(f"Context at {state.context_usage_percent:.0f}% - compaction imminent!")
208
+ print("Recommendation: Save checkpoint NOW and clear session.")
209
+ self._trigger_auto_checkpoint("emergency")
210
+ elif level == ContextLevel.CRITICAL:
211
+ print(f"\n{Colors.BOLD_RED}[CRITICAL]{Colors.RESET} Context at {state.context_usage_percent:.0f}%")
212
+ print("Recommendation: Consider wrapping up and checkpointing soon.")
213
+ self._trigger_auto_checkpoint("critical")
214
+ elif level == ContextLevel.WARNING:
215
+ print(f"\n{Colors.YELLOW}[WARNING]{Colors.RESET} Context at {state.context_usage_percent:.0f}%")
216
+ print(f"~{state.exchanges_remaining} exchanges remaining before compaction.")
217
+
218
+ def _trigger_auto_checkpoint(self, reason: str):
219
+ """Trigger automatic checkpoint at critical thresholds."""
220
+ try:
221
+ # Import checkpoint manager
222
+ sys.path.insert(0, str(SCRIPT_DIR))
223
+ from context_checkpoint import ContextCheckpointManager
224
+
225
+ manager = ContextCheckpointManager()
226
+ context_level = self.context_monitor.state.context_usage_ratio if self.context_monitor else 0.0
227
+ checkpoint_file = manager.create_checkpoint(context_level, reason=reason)
228
+ print(f"[CHECKPOINT] Saved to: {checkpoint_file.name}")
229
+
230
+ if self.context_monitor:
231
+ self.context_monitor.record_checkpoint()
232
+ except Exception as e:
233
+ print(f"{Colors.YELLOW}[WARN] Could not create auto-checkpoint: {e}{Colors.RESET}")
234
+
235
+ def _init_validation(self):
236
+ """Initialize validation loop."""
237
+ all_gates = PREFLIGHT_GATES + INTER_PHASE_GATES + POST_COMPLETION_GATES
238
+ self.validation_loop = ValidationLoop(
239
+ gates=all_gates,
240
+ config={"auto_fix_enabled": True},
241
+ story_key=self.args.story_key,
242
+ )
243
+ self.validation_context = LoopContext(
244
+ story_key=self.args.story_key,
245
+ max_iterations=3,
246
+ )
247
+
248
+ def run_preflight_validation(self) -> bool:
249
+ """Run pre-flight validation. Returns True if passed."""
250
+ if not self.validation_enabled or not self.validation_loop:
251
+ return True
252
+
253
+ print("[VALIDATION] Running pre-flight checks...")
254
+ self.validation_context.phase = "preflight"
255
+ report = self.validation_loop.run_preflight(self.validation_context)
256
+
257
+ if report.passed:
258
+ print(f"[PASS] Pre-flight validation passed ({len(report.gate_results)} gates)")
259
+ return True
260
+ else:
261
+ print(f"{Colors.RED}[FAIL] Pre-flight validation failed{Colors.RESET}")
262
+ for failure in report.failures:
263
+ print(f" - {failure.gate_name}: {failure.message}")
264
+ return False
265
+
266
+ def run_phase_validation(self, from_phase: str, to_phase: str) -> bool:
267
+ """Run inter-phase validation. Returns True if passed."""
268
+ if not self.validation_enabled or not self.validation_loop:
269
+ return True
270
+
271
+ phase_gates = get_phase_gates(from_phase, to_phase)
272
+ if not phase_gates:
273
+ return True # No gates for this transition
274
+
275
+ print(f"[VALIDATION] Checking {from_phase} -> {to_phase} transition...")
276
+ self.validation_context.phase = f"{from_phase}_to_{to_phase}"
277
+ self.validation_context.from_agent = from_phase
278
+ self.validation_context.to_agent = to_phase
279
+
280
+ # Create a temporary loop with just the phase gates
281
+ phase_loop = ValidationLoop(
282
+ gates=phase_gates,
283
+ config={"auto_fix_enabled": True},
284
+ story_key=self.args.story_key,
285
+ )
286
+ report = phase_loop.run_gates(self.validation_context, tier=2)
287
+
288
+ if report.passed:
289
+ print("[PASS] Phase transition validated")
290
+ return True
291
+ else:
292
+ print(f"{Colors.YELLOW}[WARN] Phase validation issues:{Colors.RESET}")
293
+ for failure in report.failures:
294
+ print(f" - {failure.gate_name}: {failure.message}")
295
+ # Don't block on inter-phase, just warn
296
+ return True
297
+
298
+ def run_post_validation(self) -> bool:
299
+ """Run post-completion validation. Returns True if passed."""
300
+ if not self.validation_enabled or not self.validation_loop:
301
+ return True
302
+
303
+ print("\n[VALIDATION] Running post-completion checks...")
304
+ self.validation_context.phase = "post-completion"
305
+ report = self.validation_loop.run_post_completion(self.validation_context)
306
+
307
+ if report.passed:
308
+ print("[PASS] Post-completion validation passed")
309
+ if report.warnings:
310
+ print(f"{Colors.YELLOW}[WARN] {len(report.warnings)} warning(s):{Colors.RESET}")
311
+ for warn in report.warnings:
312
+ print(f" - {warn.gate_name}: {warn.message}")
313
+ return True
314
+ else:
315
+ print(f"{Colors.YELLOW}[WARN] Post-completion validation issues:{Colors.RESET}")
316
+ for failure in report.failures:
317
+ print(f" - {failure.gate_name}: {failure.message}")
318
+ # Warn but don't fail the overall run
319
+ return True
320
+
151
321
  def start_tracking(self):
152
- """Initialize cost tracking."""
322
+ """Initialize cost tracking and status line."""
153
323
  if not self.cost_available:
154
324
  return
155
325
 
@@ -158,6 +328,13 @@ class NativeRunner:
158
328
  )
159
329
  self.display = self.CompactCostDisplay(self.tracker)
160
330
 
331
+ # Create unified status line with context + cost
332
+ if HAS_CONTEXT_MONITOR and self.context_monitor:
333
+ self.status_line = StatusLine(
334
+ context_monitor=self.context_monitor,
335
+ cost_tracker=self.tracker,
336
+ )
337
+
161
338
  def start_monitor(self):
162
339
  """Start the monitoring display thread."""
163
340
  if not self.cost_available or self.args.no_monitor:
@@ -170,7 +347,10 @@ class NativeRunner:
170
347
  def _monitor_loop(self):
171
348
  """Monitor loop for live display updates."""
172
349
  while self.running:
173
- if self.tracker:
350
+ # Use unified status line if available, otherwise fall back to cost display
351
+ if self.status_line:
352
+ self.status_line.print(newline=False)
353
+ elif self.tracker:
174
354
  self.display.print()
175
355
  time.sleep(2)
176
356
 
@@ -182,7 +362,7 @@ class NativeRunner:
182
362
 
183
363
  def run_claude(self, agent: str, model: str, prompt: str, timeout: int = 300) -> tuple:
184
364
  """Run Claude CLI and capture output."""
185
- cli = "claude.cmd" if sys.platform == "win32" else "claude"
365
+ cli = "claude.cmd" if IS_WINDOWS else "claude"
186
366
 
187
367
  cmd = [cli, "--print", "--model", model, "-p", prompt]
188
368
 
@@ -202,10 +382,14 @@ class NativeRunner:
202
382
  output = result.stdout + result.stderr
203
383
 
204
384
  # Parse token usage from output (if available)
205
- if self.tracker:
206
- tokens = self._parse_tokens(output)
207
- if tokens:
385
+ tokens = self._parse_tokens(output)
386
+ if tokens:
387
+ # Update cost tracker
388
+ if self.tracker:
208
389
  self.tracker.log_usage(agent, model, tokens[0], tokens[1])
390
+ # Update context monitor
391
+ if self.context_monitor:
392
+ self.context_monitor.update_from_tokens(tokens[0], tokens[1])
209
393
 
210
394
  return (result.returncode == 0, output)
211
395
 
@@ -243,31 +427,61 @@ class NativeRunner:
243
427
  ok, level, msg = self.tracker.check_budget()
244
428
 
245
429
  if level == "critical":
246
- print(f"\n\033[91m{msg}\033[0m")
430
+ print(f"\n{Colors.RED}{msg}{Colors.RESET}")
247
431
  elif level == "warning":
248
- print(f"\n\033[93m{msg}\033[0m")
432
+ print(f"\n{Colors.YELLOW}{msg}{Colors.RESET}")
249
433
 
250
434
  return ok
251
435
 
252
436
  def run(self) -> int:
253
437
  """Run the story automation."""
254
- print(f"Starting story: {self.args.story_key}")
255
- print(f"Model: {self.args.model}")
256
- print(f"Budget: ${self.args.budget:.2f}")
438
+ # Print header with status line
439
+ print(f"{Colors.DIM}{'─' * 70}{Colors.RESET}")
440
+ print(f"{Colors.BOLD}DEVFLOW STORY RUNNER{Colors.RESET}")
441
+ print(f"Story: {self.args.story_key} | Model: {self.args.model} | Budget: ${self.args.budget:.2f}")
442
+ if self.validation_enabled:
443
+ print("Validation: Enabled")
444
+ if self.context_monitor:
445
+ print(f"Context Monitor: Active (window: {self.context_monitor.state.context_window:,} tokens)")
446
+ print(f"{Colors.DIM}{'─' * 70}{Colors.RESET}")
257
447
  print()
258
448
 
449
+ # Run pre-flight validation
450
+ if not self.run_preflight_validation():
451
+ print(f"\n{Colors.RED}[BLOCKED] Pre-flight validation failed. Aborting.{Colors.RESET}")
452
+ return 1
453
+
259
454
  self.start_tracking()
260
455
  self.start_monitor()
261
456
 
457
+ # Print initial status line
458
+ if self.status_line:
459
+ self.status_line.print()
460
+
262
461
  try:
263
462
  # Determine which phases to run
264
463
  run_context = self.args.context or (not self.args.develop and not self.args.review)
265
464
  run_develop = self.args.develop or (not self.args.context and not self.args.review)
266
465
  run_review = self.args.review or (not self.args.context and not self.args.develop)
267
466
 
467
+ # Calculate total phases
468
+ total_phases = sum([run_context, run_develop, run_review])
469
+ phases_completed = 0
470
+
471
+ # Set initial activity state
472
+ if self.context_monitor:
473
+ self.context_monitor.set_current_activity(total_phases=total_phases, phases_completed=0)
474
+
268
475
  # Context phase
269
476
  if run_context:
270
477
  print("\n[1/3] Context Phase...")
478
+ if self.context_monitor:
479
+ self.context_monitor.set_current_activity(
480
+ agent="SM",
481
+ phase="Context Analysis",
482
+ task="Preparing development context",
483
+ phases_completed=phases_completed,
484
+ )
271
485
  success, output = self.run_claude(
272
486
  "SM",
273
487
  "sonnet",
@@ -277,12 +491,27 @@ class NativeRunner:
277
491
  print(f"Context phase failed: {output[:200]}")
278
492
  return 1
279
493
 
494
+ phases_completed += 1
495
+ if self.context_monitor:
496
+ self.context_monitor.set_current_activity(phases_completed=phases_completed)
497
+
280
498
  if not self.check_budget():
281
499
  return 1
282
500
 
501
+ # Validate context -> dev transition
502
+ if run_develop:
503
+ self.run_phase_validation("CONTEXT", "DEV")
504
+
283
505
  # Development phase
284
506
  if run_develop:
285
507
  print("\n[2/3] Development Phase...")
508
+ if self.context_monitor:
509
+ self.context_monitor.set_current_activity(
510
+ agent="DEV",
511
+ phase="Development",
512
+ task="Implementing story",
513
+ phases_completed=phases_completed,
514
+ )
286
515
  success, output = self.run_claude(
287
516
  "DEV",
288
517
  self.args.model,
@@ -292,12 +521,27 @@ class NativeRunner:
292
521
  print(f"Development phase failed: {output[:200]}")
293
522
  return 1
294
523
 
524
+ phases_completed += 1
525
+ if self.context_monitor:
526
+ self.context_monitor.set_current_activity(phases_completed=phases_completed)
527
+
295
528
  if not self.check_budget():
296
529
  return 1
297
530
 
531
+ # Validate dev -> review transition
532
+ if run_review:
533
+ self.run_phase_validation("DEV", "REVIEW")
534
+
298
535
  # Review phase
299
536
  if run_review and not self.args.context and not self.args.develop:
300
537
  print("\n[3/3] Review Phase...")
538
+ if self.context_monitor:
539
+ self.context_monitor.set_current_activity(
540
+ agent="REVIEWER",
541
+ phase="Code Review",
542
+ task="Reviewing implementation",
543
+ phases_completed=phases_completed,
544
+ )
301
545
  success, output = self.run_claude(
302
546
  "SM", "sonnet", f"Review the implementation of story {self.args.story_key}"
303
547
  )
@@ -305,8 +549,22 @@ class NativeRunner:
305
549
  print(f"Review phase failed: {output[:200]}")
306
550
  return 1
307
551
 
552
+ phases_completed += 1
553
+ if self.context_monitor:
554
+ self.context_monitor.set_current_activity(phases_completed=phases_completed)
555
+
556
+ # Validate review -> complete transition
557
+ self.run_phase_validation("REVIEW", "COMPLETE")
558
+
559
+ # Clear activity when done
560
+ if self.context_monitor:
561
+ self.context_monitor.clear_current_activity()
562
+
308
563
  print("\n[OK] Story automation complete!")
309
564
 
565
+ # Run post-completion validation
566
+ self.run_post_validation()
567
+
310
568
  # Show final costs
311
569
  if self.tracker:
312
570
  print()