@pjmendonca/devflow 1.13.2 → 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.
- package/.claude/commands/agent.md +1 -1
- package/.claude/commands/bugfix.md +21 -0
- package/.claude/commands/checkpoint.md +0 -1
- package/.claude/commands/collab.md +0 -1
- package/.claude/commands/costs.md +88 -18
- package/.claude/commands/devflow.md +26 -0
- package/.claude/commands/handoff.md +0 -1
- package/.claude/commands/init.md +287 -0
- package/.claude/commands/memory.md +0 -1
- package/.claude/commands/pair.md +0 -1
- package/.claude/commands/review.md +27 -0
- package/.claude/commands/route.md +0 -1
- package/.claude/commands/swarm.md +0 -1
- package/.claude/commands/validate.md +55 -0
- package/.claude/hooks/session-notification.sh +44 -0
- package/.claude/hooks/session-startup.sh +427 -0
- package/.claude/hooks/session-stop.sh +38 -0
- package/.claude/hooks/session_tracker.py +272 -0
- package/.claude/settings.json +38 -0
- package/.claude/skills/costs/SKILL.md +156 -0
- package/.claude/skills/validate/SKILL.md +101 -0
- package/CHANGELOG.md +243 -0
- package/README.md +207 -10
- package/bin/devflow-install.js +2 -1
- package/bin/devflow.js +4 -0
- package/lib/constants.js +0 -1
- package/lib/exec-python.js +1 -1
- package/package.json +1 -1
- package/tooling/.automation/.checkpoint_lock +1 -0
- package/tooling/.automation/agents/architect.md +19 -0
- package/tooling/.automation/agents/ba.md +19 -0
- package/tooling/.automation/agents/maintainer.md +19 -0
- package/tooling/.automation/agents/pm.md +19 -0
- package/tooling/.automation/agents/reviewer.md +1 -1
- package/tooling/.automation/agents/writer.md +19 -0
- package/tooling/.automation/benchmarks/benchmark_20251230_100119.json +314 -0
- package/tooling/.automation/benchmarks/benchmark_20251230_100216.json +314 -0
- package/tooling/.automation/costs/config.json +31 -0
- package/tooling/.automation/costs/sessions/2025-12-29_20251229_164128.json +22 -0
- package/tooling/.automation/memory/knowledge/kg_integration-test.json +707 -1
- package/tooling/.automation/memory/knowledge/kg_test-story.json +3273 -2
- package/tooling/.automation/memory/shared/shared_integration-test.json +181 -1
- package/tooling/.automation/memory/shared/shared_test-story.json +721 -1
- package/tooling/.automation/memory/shared/shared_test.json +1254 -0
- package/tooling/.automation/memory/shared/shared_validation-check.json +227 -0
- package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +5 -5
- package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +23 -5
- package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +24 -6
- package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +4 -4
- package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +4 -4
- package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +4 -4
- package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +18 -0
- package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +19 -1
- package/tooling/.automation/overrides/templates/dev/security-focused.yaml +18 -0
- package/tooling/.automation/overrides/templates/dev/user-advocate.yaml +54 -0
- package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/reliability-engineer.yaml +55 -0
- package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +4 -4
- package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +3 -3
- package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +4 -4
- package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +18 -0
- package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +18 -0
- package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +2 -2
- package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +3 -3
- package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +5 -5
- package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +4 -4
- package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +5 -5
- package/tooling/.automation/validation/history/2025-12-29_val_002a28c1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_01273bb1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_03369914.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_07a449ba.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_0df1f0a2.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_10ff3d34.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_110771d7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_13f3a7f9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_17ba9d21.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_22247089.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_227ea6a4.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2335d5ae.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_246824bb.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_28b4b9cd.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2abd12cc.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2c801b2f.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2c8cfa8e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2ce76eb0.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_30351948.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_30eb7229.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_34df0e77.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_376e4d6a.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3a4e8a1a.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3b77a628.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3ea4e1cf.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_44aacdb4.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_457ddfa8.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_45af6238.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_4735dba1.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_486b203c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_49dc56cd.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_4d863d6d.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_5149a808.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_52e0bb43.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_585d6319.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_5b2d859a.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_635a7081.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_64df4905.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_70634cee.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_714553f9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_7f7bfdbf.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_7faad91d.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_81821f8f.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8249f3c9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8422b50f.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8446c134.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_879f4e26.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8b6d5bd7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8c5cd787.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_91d20bc7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_958a12b7.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_95d91108.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_980dbb74.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9e40c79b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9f499b7c.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9f7c3b57.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a30d5bd4.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a6eb09c7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a86f7b83.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ad5347e1.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_b0a5a993.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_bcb0192e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_bf3c9aaa.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c461ff88.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c4f4e258.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c7f0fa6d.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c911b0e6.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cc581964.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cdd5a33b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cfd42495.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d1c7a4ee.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d2280d0e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d2a6ff69.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d8c53ab2.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d9c1247a.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d9d58569.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_dabb4fd9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_dd8fe359.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_decdffc9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_e3a95476.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_e776dfca.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ea70969f.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ef41ea95.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_f384f9b1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_f8adc38c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fa40b69e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fc538d54.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fe814665.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ffea4b12.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_02d001e5.json +59 -0
- package/tooling/.automation/validation/history/2025-12-30_val_0b8966dc.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_15455fbf.json +59 -0
- package/tooling/.automation/validation/history/2025-12-30_val_157e34b9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_28d1d933.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_3442a52c.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_37f1ce1e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_4f1d8a93.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_56ff1de3.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_664fd4e2.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_66afb0a7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_7634663c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_8ea830c3.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_998957c2.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_a52177db.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_a5b65a63.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ae391d0e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_c7895339.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ca416593.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_cee19422.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ddd4f4e6.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_f2e1394b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_f4a7fa06.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ffea3369.json +32 -0
- package/tooling/.automation/validation-config.yaml +103 -0
- package/tooling/completions/DevflowCompletion.ps1 +21 -21
- package/tooling/completions/_run-story +3 -3
- package/tooling/completions/run-story-completion.bash +8 -8
- package/tooling/docs/DOC-STANDARD.md +14 -14
- package/tooling/docs/templates/migration-spec.md +4 -4
- package/tooling/scripts/context_checkpoint.py +5 -15
- package/tooling/scripts/cost_dashboard.py +610 -13
- package/tooling/scripts/create-persona.py +1 -12
- package/tooling/scripts/create-persona.sh +44 -44
- package/tooling/scripts/lib/__init__.py +12 -1
- package/tooling/scripts/lib/agent_handoff.py +11 -2
- package/tooling/scripts/lib/agent_router.py +31 -10
- package/tooling/scripts/lib/colors.py +106 -0
- package/tooling/scripts/lib/context_monitor.py +766 -0
- package/tooling/scripts/lib/cost_config.py +229 -10
- package/tooling/scripts/lib/cost_display.py +20 -45
- package/tooling/scripts/lib/cost_tracker.py +462 -15
- package/tooling/scripts/lib/currency_converter.py +28 -5
- package/tooling/scripts/lib/pair_programming.py +102 -3
- package/tooling/scripts/lib/personality_system.py +949 -0
- package/tooling/scripts/lib/platform.py +55 -0
- package/tooling/scripts/lib/shared_memory.py +9 -3
- package/tooling/scripts/lib/swarm_orchestrator.py +514 -75
- package/tooling/scripts/lib/validation_loop.py +1014 -0
- package/tooling/scripts/memory_summarize.py +9 -2
- package/tooling/scripts/new-doc.py +2 -9
- package/tooling/scripts/personalize_agent.py +1 -12
- package/tooling/scripts/rollback-migration.sh +60 -60
- package/tooling/scripts/run-collab.ps1 +16 -16
- package/tooling/scripts/run-collab.py +88 -53
- package/tooling/scripts/run-collab.sh +4 -4
- package/tooling/scripts/run-story.py +278 -20
- package/tooling/scripts/run-story.sh +3 -3
- package/tooling/scripts/setup-checkpoint-service.py +2 -9
- package/tooling/scripts/tech-debt-tracker.py +1 -12
- package/tooling/scripts/test_adversarial_swarm.py +452 -0
- package/tooling/scripts/validate-overrides.py +1 -10
- package/tooling/scripts/validate-overrides.sh +40 -40
- package/tooling/scripts/validate_loop.py +162 -0
- package/tooling/scripts/validate_setup.py +2 -30
- 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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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.
|
|
67
|
-
Path(os.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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":
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
|
430
|
+
print(f"\n{Colors.RED}{msg}{Colors.RESET}")
|
|
247
431
|
elif level == "warning":
|
|
248
|
-
print(f"\n
|
|
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
|
-
|
|
255
|
-
print(f"
|
|
256
|
-
print(f"
|
|
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()
|