@pjmendonca/devflow 1.9.0 → 1.10.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/CHANGELOG.md +11 -1
- package/README.md +50 -48
- package/bin/create-devflow.js +140 -0
- package/lib/python-check.js +5 -5
- package/package.json +2 -1
- package/tooling/.automation/agents/dev.md +2 -2
- package/tooling/.automation/agents/reviewer.md +8 -8
- package/tooling/.automation/agents/sm.md +1 -1
- package/tooling/.automation/memory/knowledge/kg_integration-test.json +137 -1
- package/tooling/.automation/memory/knowledge/kg_test-story.json +438 -2
- package/tooling/.automation/memory/shared/shared_integration-test.json +25 -1
- package/tooling/.automation/memory/shared/shared_test-story.json +73 -1
- package/tooling/.automation/overrides/templates/reviewer/mentoring-reviewer.yaml +5 -5
- package/tooling/docs/DOC-STANDARD.md +21 -21
- package/tooling/docs/templates/bug-report.md +1 -1
- package/tooling/scripts/context_checkpoint.py +16 -16
- package/tooling/scripts/create-persona.py +7 -7
- package/tooling/scripts/create-persona.sh +4 -4
- package/tooling/scripts/init-project-workflow.sh +19 -19
- package/tooling/scripts/lib/__init__.py +1 -1
- package/tooling/scripts/lib/agent_handoff.py +4 -6
- package/tooling/scripts/lib/agent_router.py +6 -6
- package/tooling/scripts/lib/checkpoint-integration.sh +14 -14
- package/tooling/scripts/lib/claude-cli.sh +50 -50
- package/tooling/scripts/lib/cost_tracker.py +4 -4
- package/tooling/scripts/lib/errors.py +9 -9
- package/tooling/scripts/lib/pair_programming.py +5 -5
- package/tooling/scripts/lib/shared_memory.py +4 -4
- package/tooling/scripts/lib/swarm_orchestrator.py +18 -18
- package/tooling/scripts/new-doc.sh +12 -12
- package/tooling/scripts/personalize_agent.py +4 -4
- package/tooling/scripts/rollback-migration.sh +4 -4
- package/tooling/scripts/run-collab.ps1 +2 -2
- package/tooling/scripts/run-collab.py +13 -13
- package/tooling/scripts/run-story.py +1 -1
- package/tooling/scripts/run-story.sh +20 -20
- package/tooling/scripts/setup-checkpoint-service.sh +4 -4
- package/tooling/scripts/tech-debt-tracker.py +12 -12
- package/tooling/scripts/update_version.py +10 -10
- package/tooling/scripts/validate-overrides.py +10 -12
- package/tooling/scripts/validate-overrides.sh +7 -7
- package/tooling/scripts/validate_setup.py +8 -8
|
@@ -11,7 +11,7 @@ Orchestrates multiple agents working together with:
|
|
|
11
11
|
|
|
12
12
|
Features:
|
|
13
13
|
- Swarm mode: Multiple agents debate until consensus
|
|
14
|
-
- Iteration loops: DEV
|
|
14
|
+
- Iteration loops: DEV -> REVIEWER -> DEV cycles
|
|
15
15
|
- Parallel execution: Independent agents run simultaneously
|
|
16
16
|
- Voting mechanisms for decisions
|
|
17
17
|
- Automatic termination on convergence
|
|
@@ -171,9 +171,9 @@ class SwarmResult:
|
|
|
171
171
|
]
|
|
172
172
|
|
|
173
173
|
if self.state == SwarmState.CONSENSUS:
|
|
174
|
-
lines.append("
|
|
174
|
+
lines.append(" **Consensus reached!**")
|
|
175
175
|
elif self.state == SwarmState.MAX_ITERATIONS:
|
|
176
|
-
lines.append("
|
|
176
|
+
lines.append(" **Max iterations reached without full consensus**")
|
|
177
177
|
|
|
178
178
|
lines.append("")
|
|
179
179
|
lines.append("### Final Output")
|
|
@@ -244,11 +244,11 @@ class SwarmOrchestrator:
|
|
|
244
244
|
if self.config.verbose:
|
|
245
245
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
|
246
246
|
emoji = {
|
|
247
|
-
"INFO": "
|
|
248
|
-
"SUCCESS": "
|
|
249
|
-
"WARNING": "
|
|
250
|
-
"ERROR": "
|
|
251
|
-
"DEBUG": "
|
|
247
|
+
"INFO": "[INFO]",
|
|
248
|
+
"SUCCESS": "",
|
|
249
|
+
"WARNING": "",
|
|
250
|
+
"ERROR": "",
|
|
251
|
+
"DEBUG": "",
|
|
252
252
|
}.get(level, "•")
|
|
253
253
|
print(f"[{timestamp}] {emoji} {message}")
|
|
254
254
|
|
|
@@ -326,7 +326,7 @@ class SwarmOrchestrator:
|
|
|
326
326
|
issues = []
|
|
327
327
|
patterns = [
|
|
328
328
|
r"(?:issue|problem|bug|error|fix needed|must fix|should fix):\s*(.+)",
|
|
329
|
-
r"
|
|
329
|
+
r"\s*(.+)",
|
|
330
330
|
r"\[ISSUE\]\s*(.+)",
|
|
331
331
|
r"- (?:Issue|Problem|Bug):\s*(.+)",
|
|
332
332
|
]
|
|
@@ -342,7 +342,7 @@ class SwarmOrchestrator:
|
|
|
342
342
|
approvals = []
|
|
343
343
|
patterns = [
|
|
344
344
|
r"(?:lgtm|approved|looks good|well done|excellent)[\s:]*(.+)?",
|
|
345
|
-
r"
|
|
345
|
+
r"\s*(.+)",
|
|
346
346
|
r"\[APPROVED\]\s*(.+)?",
|
|
347
347
|
]
|
|
348
348
|
|
|
@@ -358,7 +358,7 @@ class SwarmOrchestrator:
|
|
|
358
358
|
suggestions = []
|
|
359
359
|
patterns = [
|
|
360
360
|
r"(?:suggest|consider|recommend|might want to|could):\s*(.+)",
|
|
361
|
-
r"
|
|
361
|
+
r"\s*(.+)",
|
|
362
362
|
r"\[SUGGESTION\]\s*(.+)",
|
|
363
363
|
]
|
|
364
364
|
|
|
@@ -470,15 +470,15 @@ At the end, clearly indicate if you APPROVE or have ISSUES with the work.
|
|
|
470
470
|
if r.issues_found:
|
|
471
471
|
feedback_lines.append("**Issues found:**")
|
|
472
472
|
for issue in r.issues_found:
|
|
473
|
-
feedback_lines.append(f"-
|
|
473
|
+
feedback_lines.append(f"- {issue}")
|
|
474
474
|
if r.suggestions:
|
|
475
475
|
feedback_lines.append("**Suggestions:**")
|
|
476
476
|
for sug in r.suggestions:
|
|
477
|
-
feedback_lines.append(f"-
|
|
477
|
+
feedback_lines.append(f"- {sug}")
|
|
478
478
|
if r.approvals:
|
|
479
479
|
feedback_lines.append("**Approvals:**")
|
|
480
480
|
for app in r.approvals:
|
|
481
|
-
feedback_lines.append(f"-
|
|
481
|
+
feedback_lines.append(f"- {app}")
|
|
482
482
|
feedback_lines.append("")
|
|
483
483
|
|
|
484
484
|
prompt = f"""You are the {agent} agent. This is iteration {iteration + 1}.
|
|
@@ -573,7 +573,7 @@ At the end, clearly indicate if you APPROVE the current state or have remaining
|
|
|
573
573
|
previous_responses = iter_responses
|
|
574
574
|
|
|
575
575
|
self._log(f"Issues remaining: {len(issues_to_fix)}")
|
|
576
|
-
self._log(f"Consensus: {'
|
|
576
|
+
self._log(f"Consensus: {' Yes' if consensus else ' No'}")
|
|
577
577
|
|
|
578
578
|
if consensus:
|
|
579
579
|
self.state = SwarmState.CONSENSUS
|
|
@@ -630,7 +630,7 @@ At the end, clearly indicate if you APPROVE the current state or have remaining
|
|
|
630
630
|
task: str,
|
|
631
631
|
max_iterations: Optional[int] = None,
|
|
632
632
|
) -> SwarmResult:
|
|
633
|
-
"""Run a simple iteration loop between two agents (e.g., DEV
|
|
633
|
+
"""Run a simple iteration loop between two agents (e.g., DEV -> REVIEWER -> DEV)."""
|
|
634
634
|
return self.run_swarm(
|
|
635
635
|
agents=[primary_agent, reviewer_agent], task=task, max_iterations=max_iterations
|
|
636
636
|
)
|
|
@@ -647,7 +647,7 @@ def run_swarm(
|
|
|
647
647
|
|
|
648
648
|
|
|
649
649
|
def run_dev_review_loop(story_key: str, task: str, max_iterations: int = 3) -> SwarmResult:
|
|
650
|
-
"""Run a DEV
|
|
650
|
+
"""Run a DEV -> REVIEWER iteration loop."""
|
|
651
651
|
config = SwarmConfig(
|
|
652
652
|
max_iterations=max_iterations, consensus_type=ConsensusType.REVIEWER_APPROVAL
|
|
653
653
|
)
|
|
@@ -680,7 +680,7 @@ if __name__ == "__main__":
|
|
|
680
680
|
)
|
|
681
681
|
print(result.to_summary())
|
|
682
682
|
|
|
683
|
-
# Simple DEV
|
|
683
|
+
# Simple DEV -> REVIEWER loop
|
|
684
684
|
result = run_dev_review_loop(
|
|
685
685
|
story_key="3-5",
|
|
686
686
|
task="Implement login endpoint",
|
|
@@ -354,24 +354,24 @@ create_status_template() {
|
|
|
354
354
|
|
|
355
355
|
| Component | Status | Notes |
|
|
356
356
|
|-----------|--------|-------|
|
|
357
|
-
| Component 1 |
|
|
358
|
-
| Component 2 |
|
|
359
|
-
| Component 3 |
|
|
357
|
+
| Component 1 | Complete | Working as expected |
|
|
358
|
+
| Component 2 | In Progress | 75% complete |
|
|
359
|
+
| Component 3 | Not Started | Planned for next week |
|
|
360
360
|
|
|
361
361
|
---
|
|
362
362
|
|
|
363
363
|
## What's Working
|
|
364
364
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
365
|
+
Feature 1 - Fully operational
|
|
366
|
+
Feature 2 - Deployed and tested
|
|
367
|
+
Feature 3 - In production
|
|
368
368
|
|
|
369
369
|
---
|
|
370
370
|
|
|
371
371
|
## What's Not Working
|
|
372
372
|
|
|
373
|
-
|
|
374
|
-
|
|
373
|
+
Issue 1 - Description
|
|
374
|
+
Issue 2 - Description
|
|
375
375
|
|
|
376
376
|
---
|
|
377
377
|
|
|
@@ -379,9 +379,9 @@ create_status_template() {
|
|
|
379
379
|
|
|
380
380
|
| Metric | Value | Target | Status |
|
|
381
381
|
|--------|-------|--------|--------|
|
|
382
|
-
| Coverage | 85% | 80% |
|
|
383
|
-
| Performance | 200ms | <300ms |
|
|
384
|
-
| Bugs | 3 | <5 |
|
|
382
|
+
| Coverage | 85% | 80% | |
|
|
383
|
+
| Performance | 200ms | <300ms | |
|
|
384
|
+
| Bugs | 3 | <5 | |
|
|
385
385
|
|
|
386
386
|
---
|
|
387
387
|
|
|
@@ -521,7 +521,7 @@ main() {
|
|
|
521
521
|
# Write file
|
|
522
522
|
echo "$template" > "$output_file"
|
|
523
523
|
|
|
524
|
-
echo -e "${GREEN}
|
|
524
|
+
echo -e "${GREEN} Created: $output_file${NC}"
|
|
525
525
|
echo ""
|
|
526
526
|
echo -e "${BLUE}Next steps:${NC}"
|
|
527
527
|
echo " 1. Edit the document: $output_file"
|
|
@@ -84,7 +84,7 @@ def prompt_choice(prompt: str, options: list[str], default: int = 0) -> int:
|
|
|
84
84
|
"""Prompt user to choose from options."""
|
|
85
85
|
print(f"{Colors.YELLOW}{prompt}{Colors.END}")
|
|
86
86
|
for i, opt in enumerate(options):
|
|
87
|
-
marker = "
|
|
87
|
+
marker = "->" if i == default else " "
|
|
88
88
|
print(f" {marker} [{i + 1}] {opt}")
|
|
89
89
|
|
|
90
90
|
while True:
|
|
@@ -305,7 +305,7 @@ def save_override(agent_name: str, override: dict):
|
|
|
305
305
|
content += write_yaml(override)
|
|
306
306
|
|
|
307
307
|
override_path.write_text(content)
|
|
308
|
-
print(f"\n{Colors.GREEN}
|
|
308
|
+
print(f"\n{Colors.GREEN} Saved: {override_path}{Colors.END}")
|
|
309
309
|
|
|
310
310
|
|
|
311
311
|
def main():
|
|
@@ -345,7 +345,7 @@ def main():
|
|
|
345
345
|
for key, value in values.items():
|
|
346
346
|
content += f' {key}: "{value}"\n'
|
|
347
347
|
profile_path.write_text(content)
|
|
348
|
-
print(f"\n{Colors.GREEN}
|
|
348
|
+
print(f"\n{Colors.GREEN} User profile saved{Colors.END}")
|
|
349
349
|
|
|
350
350
|
# Determine agents to personalize
|
|
351
351
|
agents = get_available_agents()
|
|
@@ -375,7 +375,7 @@ def main():
|
|
|
375
375
|
if override:
|
|
376
376
|
save_override(agent, override)
|
|
377
377
|
|
|
378
|
-
print(f"\n{Colors.GREEN}{Colors.BOLD}
|
|
378
|
+
print(f"\n{Colors.GREEN}{Colors.BOLD} Personalization complete!{Colors.END}")
|
|
379
379
|
print(f"\nYour overrides are in: {OVERRIDES_DIR}")
|
|
380
380
|
print("They will be applied automatically when running agents.")
|
|
381
381
|
print("\nTo modify later, edit the .override.yaml files directly.")
|
|
@@ -48,20 +48,20 @@ print_header() {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
error() {
|
|
51
|
-
echo -e "${RED}
|
|
51
|
+
echo -e "${RED}[X] ERROR:${NC} $1"
|
|
52
52
|
exit 1
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
warning() {
|
|
56
|
-
echo -e "${YELLOW}
|
|
56
|
+
echo -e "${YELLOW}WARNING:${NC} $1"
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
success() {
|
|
60
|
-
echo -e "${GREEN}
|
|
60
|
+
echo -e "${GREEN}[OK]${NC} $1"
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
info() {
|
|
64
|
-
echo -e "${BLUE}
|
|
64
|
+
echo -e "${BLUE}[i]${NC} $1"
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
confirm() {
|
|
@@ -242,10 +242,10 @@ $exitCode = $LASTEXITCODE
|
|
|
242
242
|
if ($exitCode -eq 0) {
|
|
243
243
|
Write-Host ""
|
|
244
244
|
Write-ColorOutput "════════════════════════════════════════════════════════════" -Color Green
|
|
245
|
-
Write-ColorOutput "
|
|
245
|
+
Write-ColorOutput " Collaboration complete!" -Color Green
|
|
246
246
|
} else {
|
|
247
247
|
Write-Host ""
|
|
248
|
-
Write-ColorOutput "
|
|
248
|
+
Write-ColorOutput " Failed with exit code: $exitCode" -Color Red
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
exit $exitCode
|
|
@@ -218,7 +218,7 @@ def print_banner():
|
|
|
218
218
|
|
|
219
219
|
def print_routing_decision(result: RoutingResult, router: AgentRouter):
|
|
220
220
|
"""Print the routing decision."""
|
|
221
|
-
print(f"\n{Colors.BOLD}
|
|
221
|
+
print(f"\n{Colors.BOLD}Routing Decision{Colors.END}")
|
|
222
222
|
print(router.explain_routing(result))
|
|
223
223
|
|
|
224
224
|
|
|
@@ -240,13 +240,13 @@ def run_auto_mode(story_key: str, task: str, args: argparse.Namespace):
|
|
|
240
240
|
|
|
241
241
|
# Decide execution mode based on routing
|
|
242
242
|
if result.workflow == "swarm":
|
|
243
|
-
print(f"\n{Colors.YELLOW}
|
|
243
|
+
print(f"\n{Colors.YELLOW}-> Using swarm mode for multi-agent collaboration{Colors.END}")
|
|
244
244
|
return run_swarm_mode(story_key, task, result.agents, args)
|
|
245
245
|
elif result.workflow == "pair":
|
|
246
|
-
print(f"\n{Colors.YELLOW}
|
|
246
|
+
print(f"\n{Colors.YELLOW}-> Using pair programming mode{Colors.END}")
|
|
247
247
|
return run_pair_mode(story_key, task, args)
|
|
248
248
|
else:
|
|
249
|
-
print(f"\n{Colors.YELLOW}
|
|
249
|
+
print(f"\n{Colors.YELLOW}-> Using sequential execution{Colors.END}")
|
|
250
250
|
return run_sequential_mode(story_key, task, result.agents, args)
|
|
251
251
|
|
|
252
252
|
|
|
@@ -299,7 +299,7 @@ def run_pair_mode(story_key: str, task: str, args: argparse.Namespace):
|
|
|
299
299
|
|
|
300
300
|
def run_sequential_mode(story_key: str, task: str, agents: list[str], args: argparse.Namespace):
|
|
301
301
|
"""Run sequential agent execution with handoffs."""
|
|
302
|
-
print_section("Sequential Mode", f"Pipeline: {'
|
|
302
|
+
print_section("Sequential Mode", f"Pipeline: {' -> '.join(agents)}")
|
|
303
303
|
|
|
304
304
|
get_shared_memory(story_key)
|
|
305
305
|
get_knowledge_graph(story_key)
|
|
@@ -309,7 +309,7 @@ def run_sequential_mode(story_key: str, task: str, agents: list[str], args: argp
|
|
|
309
309
|
previous_output = ""
|
|
310
310
|
|
|
311
311
|
for i, agent in enumerate(agents):
|
|
312
|
-
print(f"\n{Colors.CYAN}
|
|
312
|
+
print(f"\n{Colors.CYAN}> Running {agent}...{Colors.END}")
|
|
313
313
|
|
|
314
314
|
# Get context including handoffs
|
|
315
315
|
context = handoff_gen.generate_context_for_agent(agent)
|
|
@@ -329,7 +329,7 @@ Complete your part of this task according to your role.
|
|
|
329
329
|
"""
|
|
330
330
|
|
|
331
331
|
# Invoke agent (simplified - in real use would call Claude CLI)
|
|
332
|
-
print("
|
|
332
|
+
print(" -> Generating response...")
|
|
333
333
|
|
|
334
334
|
# For demo, we'll note the handoff
|
|
335
335
|
if i > 0:
|
|
@@ -340,7 +340,7 @@ Complete your part of this task according to your role.
|
|
|
340
340
|
story_key=story_key,
|
|
341
341
|
summary=f"Completed {prev_agent} phase, handing off to {agent}",
|
|
342
342
|
)
|
|
343
|
-
print(f"
|
|
343
|
+
print(f" -> Handoff from {prev_agent}: {handoff.id}")
|
|
344
344
|
|
|
345
345
|
# Record in shared memory
|
|
346
346
|
share_learning(
|
|
@@ -351,7 +351,7 @@ Complete your part of this task according to your role.
|
|
|
351
351
|
{"agent": agent, "status": "completed", "timestamp": datetime.now().isoformat()}
|
|
352
352
|
)
|
|
353
353
|
|
|
354
|
-
print(f"\n{Colors.GREEN}
|
|
354
|
+
print(f"\n{Colors.GREEN} Sequential pipeline complete!{Colors.END}")
|
|
355
355
|
|
|
356
356
|
# Save result
|
|
357
357
|
save_result(story_key, "sequential", {"agents": agents, "results": results})
|
|
@@ -388,7 +388,7 @@ def save_result(story_key: str, mode: str, result: dict):
|
|
|
388
388
|
ensure_ascii=False,
|
|
389
389
|
)
|
|
390
390
|
|
|
391
|
-
print(f"\n{Colors.CYAN}
|
|
391
|
+
print(f"\n{Colors.CYAN} Result saved to: {filepath}{Colors.END}")
|
|
392
392
|
|
|
393
393
|
|
|
394
394
|
def show_memory(story_key: str):
|
|
@@ -586,14 +586,14 @@ def main():
|
|
|
586
586
|
run_auto_mode(story_key, task, args)
|
|
587
587
|
|
|
588
588
|
print(f"\n{Colors.GREEN}{'═' * 60}{Colors.END}")
|
|
589
|
-
print(f"{Colors.GREEN}
|
|
589
|
+
print(f"{Colors.GREEN} Collaboration complete!{Colors.END}")
|
|
590
590
|
return 0
|
|
591
591
|
|
|
592
592
|
except KeyboardInterrupt:
|
|
593
|
-
print(f"\n{Colors.YELLOW}
|
|
593
|
+
print(f"\n{Colors.YELLOW} Interrupted by user{Colors.END}")
|
|
594
594
|
return 130
|
|
595
595
|
except Exception as e:
|
|
596
|
-
print(f"\n{Colors.RED}
|
|
596
|
+
print(f"\n{Colors.RED} Error: {e}{Colors.END}")
|
|
597
597
|
if not args.quiet:
|
|
598
598
|
import traceback
|
|
599
599
|
|
|
@@ -252,7 +252,7 @@ main() {
|
|
|
252
252
|
|
|
253
253
|
# Check for existing checkpoint and offer to resume
|
|
254
254
|
if type has_checkpoint &>/dev/null && has_checkpoint "$story_key"; then
|
|
255
|
-
echo -e "${CYAN}
|
|
255
|
+
echo -e "${CYAN} Found existing checkpoint for story: $story_key${NC}"
|
|
256
256
|
echo -e "${YELLOW}Would you like to resume from the checkpoint? (y/n)${NC}"
|
|
257
257
|
read -r RESUME_CHOICE
|
|
258
258
|
|
|
@@ -269,7 +269,7 @@ main() {
|
|
|
269
269
|
|
|
270
270
|
# Create pre-start checkpoint
|
|
271
271
|
if type create_story_checkpoint &>/dev/null; then
|
|
272
|
-
echo -e "${CYAN}
|
|
272
|
+
echo -e "${CYAN} Creating pre-start checkpoint...${NC}"
|
|
273
273
|
create_story_checkpoint "$story_key" "pre-start" 2>&1 | grep -v "Could not export"
|
|
274
274
|
echo ""
|
|
275
275
|
fi
|
|
@@ -279,7 +279,7 @@ main() {
|
|
|
279
279
|
# COLLABORATIVE MODES - Multi-agent collaboration
|
|
280
280
|
# ═══════════════════════════════════════════════════════════════
|
|
281
281
|
"swarm")
|
|
282
|
-
echo -e "${YELLOW}
|
|
282
|
+
echo -e "${YELLOW}> Running swarm mode (multi-agent debate)...${NC}"
|
|
283
283
|
echo ""
|
|
284
284
|
local swarm_args="$story_key --swarm"
|
|
285
285
|
if [[ -n "$collab_agents" ]]; then
|
|
@@ -294,7 +294,7 @@ main() {
|
|
|
294
294
|
fi
|
|
295
295
|
;;
|
|
296
296
|
"pair")
|
|
297
|
-
echo -e "${YELLOW}
|
|
297
|
+
echo -e "${YELLOW}> Running pair programming mode (DEV + REVIEWER)...${NC}"
|
|
298
298
|
echo ""
|
|
299
299
|
python3 "$SCRIPT_DIR/run-collab.py" "$story_key" --pair --max-revisions "$max_iterations"
|
|
300
300
|
local exit_code=$?
|
|
@@ -304,7 +304,7 @@ main() {
|
|
|
304
304
|
fi
|
|
305
305
|
;;
|
|
306
306
|
"auto-route")
|
|
307
|
-
echo -e "${YELLOW}
|
|
307
|
+
echo -e "${YELLOW}> Running auto-route mode (intelligent agent selection)...${NC}"
|
|
308
308
|
echo ""
|
|
309
309
|
python3 "$SCRIPT_DIR/run-collab.py" "$story_key" --auto
|
|
310
310
|
local exit_code=$?
|
|
@@ -318,7 +318,7 @@ main() {
|
|
|
318
318
|
# GREENFIELD MODES - New feature development
|
|
319
319
|
# ═══════════════════════════════════════════════════════════════
|
|
320
320
|
"develop")
|
|
321
|
-
echo -e "${YELLOW}
|
|
321
|
+
echo -e "${YELLOW}> Running development phase...${NC}"
|
|
322
322
|
echo ""
|
|
323
323
|
invoke_dev_story "$story_key"
|
|
324
324
|
local exit_code=$?
|
|
@@ -339,19 +339,19 @@ main() {
|
|
|
339
339
|
fi
|
|
340
340
|
;;
|
|
341
341
|
"review")
|
|
342
|
-
echo -e "${YELLOW}
|
|
342
|
+
echo -e "${YELLOW}> Running review phase...${NC}"
|
|
343
343
|
echo ""
|
|
344
344
|
invoke_sm_code_review "$story_key"
|
|
345
345
|
exit_code=$?
|
|
346
346
|
;;
|
|
347
347
|
"adversarial")
|
|
348
|
-
echo -e "${YELLOW}
|
|
348
|
+
echo -e "${YELLOW}> Running adversarial review (Opus)...${NC}"
|
|
349
349
|
echo ""
|
|
350
350
|
invoke_adversarial_review "$story_key"
|
|
351
351
|
exit_code=$?
|
|
352
352
|
;;
|
|
353
353
|
"context")
|
|
354
|
-
echo -e "${YELLOW}
|
|
354
|
+
echo -e "${YELLOW}> Creating story context...${NC}"
|
|
355
355
|
echo ""
|
|
356
356
|
invoke_sm_story_context "$story_key"
|
|
357
357
|
exit_code=$?
|
|
@@ -361,7 +361,7 @@ main() {
|
|
|
361
361
|
# BROWNFIELD MODES - Existing codebase maintenance
|
|
362
362
|
# ═══════════════════════════════════════════════════════════════
|
|
363
363
|
"bugfix")
|
|
364
|
-
echo -e "${YELLOW}
|
|
364
|
+
echo -e "${YELLOW}> Running bug fix workflow...${NC}"
|
|
365
365
|
echo ""
|
|
366
366
|
invoke_bugfix "$story_key"
|
|
367
367
|
exit_code=$?
|
|
@@ -372,7 +372,7 @@ main() {
|
|
|
372
372
|
fi
|
|
373
373
|
;;
|
|
374
374
|
"refactor")
|
|
375
|
-
echo -e "${YELLOW}
|
|
375
|
+
echo -e "${YELLOW}> Running refactoring workflow...${NC}"
|
|
376
376
|
echo ""
|
|
377
377
|
invoke_refactor "$story_key"
|
|
378
378
|
exit_code=$?
|
|
@@ -383,14 +383,14 @@ main() {
|
|
|
383
383
|
fi
|
|
384
384
|
;;
|
|
385
385
|
"investigate")
|
|
386
|
-
echo -e "${YELLOW}
|
|
386
|
+
echo -e "${YELLOW}> Running investigation workflow...${NC}"
|
|
387
387
|
echo ""
|
|
388
388
|
invoke_investigate "$story_key"
|
|
389
389
|
exit_code=$?
|
|
390
390
|
# No auto-commit for investigation (read-only)
|
|
391
391
|
;;
|
|
392
392
|
"quickfix")
|
|
393
|
-
echo -e "${YELLOW}
|
|
393
|
+
echo -e "${YELLOW}> Running quick fix...${NC}"
|
|
394
394
|
echo ""
|
|
395
395
|
invoke_quickfix "$story_key"
|
|
396
396
|
exit_code=$?
|
|
@@ -401,7 +401,7 @@ main() {
|
|
|
401
401
|
fi
|
|
402
402
|
;;
|
|
403
403
|
"migrate")
|
|
404
|
-
echo -e "${YELLOW}
|
|
404
|
+
echo -e "${YELLOW}> Running migration workflow...${NC}"
|
|
405
405
|
echo ""
|
|
406
406
|
invoke_migrate "$story_key"
|
|
407
407
|
exit_code=$?
|
|
@@ -412,7 +412,7 @@ main() {
|
|
|
412
412
|
fi
|
|
413
413
|
;;
|
|
414
414
|
"tech-debt")
|
|
415
|
-
echo -e "${YELLOW}
|
|
415
|
+
echo -e "${YELLOW}> Running technical debt resolution...${NC}"
|
|
416
416
|
echo ""
|
|
417
417
|
invoke_tech_debt "$story_key"
|
|
418
418
|
exit_code=$?
|
|
@@ -427,7 +427,7 @@ main() {
|
|
|
427
427
|
# DEFAULT - Full greenfield pipeline
|
|
428
428
|
# ═══════════════════════════════════════════════════════════════
|
|
429
429
|
*)
|
|
430
|
-
echo -e "${YELLOW}
|
|
430
|
+
echo -e "${YELLOW}> Running full pipeline...${NC}"
|
|
431
431
|
echo ""
|
|
432
432
|
run_full_pipeline "$story_key"
|
|
433
433
|
exit_code=$?
|
|
@@ -437,7 +437,7 @@ main() {
|
|
|
437
437
|
# Create completion checkpoint if successful
|
|
438
438
|
if [[ $exit_code -eq 0 && "$mode" != "context" ]]; then
|
|
439
439
|
if type create_story_checkpoint &>/dev/null; then
|
|
440
|
-
echo -e "${CYAN}
|
|
440
|
+
echo -e "${CYAN} Creating completion checkpoint...${NC}"
|
|
441
441
|
create_story_checkpoint "$story_key" "complete" 2>&1 | grep -v "Could not export"
|
|
442
442
|
echo ""
|
|
443
443
|
fi
|
|
@@ -445,15 +445,15 @@ main() {
|
|
|
445
445
|
|
|
446
446
|
# Cleanup old checkpoints (keep last 10)
|
|
447
447
|
if type cleanup_old_checkpoints &>/dev/null; then
|
|
448
|
-
cleanup_old_checkpoints 10 2>&1 | grep -E "^(
|
|
448
|
+
cleanup_old_checkpoints 10 2>&1 | grep -E "^(||Deleted)"
|
|
449
449
|
echo ""
|
|
450
450
|
fi
|
|
451
451
|
|
|
452
452
|
echo ""
|
|
453
453
|
if [[ $exit_code -eq 0 ]]; then
|
|
454
|
-
echo -e "${GREEN}
|
|
454
|
+
echo -e "${GREEN} Complete!${NC}"
|
|
455
455
|
else
|
|
456
|
-
echo -e "${RED}
|
|
456
|
+
echo -e "${RED} Failed with exit code: $exit_code${NC}"
|
|
457
457
|
fi
|
|
458
458
|
|
|
459
459
|
echo ""
|
|
@@ -30,19 +30,19 @@ print_header() {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
print_success() {
|
|
33
|
-
echo -e "${GREEN}
|
|
33
|
+
echo -e "${GREEN} $1${NC}"
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
print_error() {
|
|
37
|
-
echo -e "${RED}
|
|
37
|
+
echo -e "${RED} $1${NC}"
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
print_info() {
|
|
41
|
-
echo -e "${BLUE}
|
|
41
|
+
echo -e "${BLUE}$1${NC}"
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
print_warning() {
|
|
45
|
-
echo -e "${YELLOW}
|
|
45
|
+
echo -e "${YELLOW} $1${NC}"
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
# Check if script exists
|
|
@@ -370,7 +370,7 @@ def print_dashboard(report: DebtReport, history: list[dict[str, Any]]):
|
|
|
370
370
|
print()
|
|
371
371
|
|
|
372
372
|
# Summary box
|
|
373
|
-
print(f"{Colors.BOLD}
|
|
373
|
+
print(f"{Colors.BOLD} SUMMARY{Colors.NC}")
|
|
374
374
|
print(f" ┌{'─' * 40}┐")
|
|
375
375
|
print(f" │ {'Total Items:':<20} {report.total_count:>17} │")
|
|
376
376
|
print(f" │ {'Debt Score:':<20} {report.debt_score:>17} │")
|
|
@@ -379,7 +379,7 @@ def print_dashboard(report: DebtReport, history: list[dict[str, Any]]):
|
|
|
379
379
|
print()
|
|
380
380
|
|
|
381
381
|
# Severity breakdown
|
|
382
|
-
print(f"{Colors.BOLD}
|
|
382
|
+
print(f"{Colors.BOLD}BY SEVERITY{Colors.NC}")
|
|
383
383
|
severity_colors = {
|
|
384
384
|
"critical": Colors.RED,
|
|
385
385
|
"high": Colors.YELLOW,
|
|
@@ -395,7 +395,7 @@ def print_dashboard(report: DebtReport, history: list[dict[str, Any]]):
|
|
|
395
395
|
print()
|
|
396
396
|
|
|
397
397
|
# Category breakdown
|
|
398
|
-
print(f"{Colors.BOLD}
|
|
398
|
+
print(f"{Colors.BOLD} BY CATEGORY{Colors.NC}")
|
|
399
399
|
for category, count in sorted(report.by_category.items(), key=lambda x: -x[1]):
|
|
400
400
|
bar_length = (
|
|
401
401
|
int((count / max(report.by_category.values())) * 30) if report.by_category else 0
|
|
@@ -405,14 +405,14 @@ def print_dashboard(report: DebtReport, history: list[dict[str, Any]]):
|
|
|
405
405
|
print()
|
|
406
406
|
|
|
407
407
|
# Type breakdown
|
|
408
|
-
print(f"{Colors.BOLD}
|
|
408
|
+
print(f"{Colors.BOLD}BY TYPE{Colors.NC}")
|
|
409
409
|
for debt_type, count in sorted(report.by_type.items(), key=lambda x: -x[1]):
|
|
410
410
|
print(f" {debt_type:>12}: {count}")
|
|
411
411
|
print()
|
|
412
412
|
|
|
413
413
|
# Trend (if history available)
|
|
414
414
|
if len(history) > 1:
|
|
415
|
-
print(f"{Colors.BOLD}
|
|
415
|
+
print(f"{Colors.BOLD}TREND (last 10 scans){Colors.NC}")
|
|
416
416
|
recent = history[-10:]
|
|
417
417
|
scores = [h.get("score", 0) for h in recent]
|
|
418
418
|
max_score = max(scores) if scores else 1
|
|
@@ -428,17 +428,17 @@ def print_dashboard(report: DebtReport, history: list[dict[str, Any]]):
|
|
|
428
428
|
if len(scores) >= 2:
|
|
429
429
|
change = scores[-1] - scores[-2]
|
|
430
430
|
if change > 0:
|
|
431
|
-
print(f"\n {Colors.RED}
|
|
431
|
+
print(f"\n {Colors.RED}[UP] Score increased by {change} (more debt){Colors.NC}")
|
|
432
432
|
elif change < 0:
|
|
433
433
|
print(
|
|
434
|
-
f"\n {Colors.GREEN}
|
|
434
|
+
f"\n {Colors.GREEN}[DOWN] Score decreased by {abs(change)} (less debt){Colors.NC}"
|
|
435
435
|
)
|
|
436
436
|
else:
|
|
437
|
-
print(f"\n {Colors.YELLOW}
|
|
437
|
+
print(f"\n {Colors.YELLOW}-> Score unchanged{Colors.NC}")
|
|
438
438
|
print()
|
|
439
439
|
|
|
440
440
|
# Top offenders
|
|
441
|
-
print(f"{Colors.BOLD}
|
|
441
|
+
print(f"{Colors.BOLD}TOP 5 FILES WITH MOST DEBT{Colors.NC}")
|
|
442
442
|
file_counts: dict[str, int] = {}
|
|
443
443
|
for item in report.items:
|
|
444
444
|
file_counts[item.file_path] = file_counts.get(item.file_path, 0) + 1
|
|
@@ -469,7 +469,7 @@ def print_report(report: DebtReport):
|
|
|
469
469
|
by_file[item.file_path].append(item)
|
|
470
470
|
|
|
471
471
|
for file_path, items in sorted(by_file.items()):
|
|
472
|
-
print(f"{Colors.BLUE}
|
|
472
|
+
print(f"{Colors.BLUE}{file_path}{Colors.NC}")
|
|
473
473
|
for item in items:
|
|
474
474
|
severity_color = {
|
|
475
475
|
"critical": Colors.RED,
|
|
@@ -485,9 +485,9 @@ def print_report(report: DebtReport):
|
|
|
485
485
|
|
|
486
486
|
# Documented debt
|
|
487
487
|
if report.documented_debt:
|
|
488
|
-
print(f"{Colors.BOLD}
|
|
488
|
+
print(f"{Colors.BOLD} DOCUMENTED DEBT{Colors.NC}")
|
|
489
489
|
for doc in report.documented_debt:
|
|
490
|
-
print(f"
|
|
490
|
+
print(f" {doc['file']}")
|
|
491
491
|
print()
|
|
492
492
|
|
|
493
493
|
|