devsquad 3.6.0__py3-none-any.whl

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 (95) hide show
  1. devsquad-3.6.0.dist-info/METADATA +944 -0
  2. devsquad-3.6.0.dist-info/RECORD +95 -0
  3. devsquad-3.6.0.dist-info/WHEEL +5 -0
  4. devsquad-3.6.0.dist-info/entry_points.txt +2 -0
  5. devsquad-3.6.0.dist-info/licenses/LICENSE +21 -0
  6. devsquad-3.6.0.dist-info/top_level.txt +2 -0
  7. scripts/__init__.py +0 -0
  8. scripts/ai_semantic_matcher.py +512 -0
  9. scripts/alert_manager.py +505 -0
  10. scripts/api/__init__.py +43 -0
  11. scripts/api/models.py +386 -0
  12. scripts/api/routes/__init__.py +20 -0
  13. scripts/api/routes/dispatch.py +348 -0
  14. scripts/api/routes/lifecycle.py +330 -0
  15. scripts/api/routes/metrics_gates.py +347 -0
  16. scripts/api_server.py +318 -0
  17. scripts/auth.py +451 -0
  18. scripts/cli/__init__.py +1 -0
  19. scripts/cli/cli_visual.py +642 -0
  20. scripts/cli.py +1094 -0
  21. scripts/collaboration/__init__.py +212 -0
  22. scripts/collaboration/_version.py +1 -0
  23. scripts/collaboration/agent_briefing.py +656 -0
  24. scripts/collaboration/ai_semantic_matcher.py +260 -0
  25. scripts/collaboration/anchor_checker.py +281 -0
  26. scripts/collaboration/anti_rationalization.py +470 -0
  27. scripts/collaboration/async_integration_example.py +255 -0
  28. scripts/collaboration/batch_scheduler.py +149 -0
  29. scripts/collaboration/checkpoint_manager.py +561 -0
  30. scripts/collaboration/ci_feedback_adapter.py +351 -0
  31. scripts/collaboration/code_map_generator.py +247 -0
  32. scripts/collaboration/concern_pack_loader.py +352 -0
  33. scripts/collaboration/confidence_score.py +496 -0
  34. scripts/collaboration/config_loader.py +188 -0
  35. scripts/collaboration/consensus.py +244 -0
  36. scripts/collaboration/context_compressor.py +533 -0
  37. scripts/collaboration/coordinator.py +668 -0
  38. scripts/collaboration/dispatcher.py +1636 -0
  39. scripts/collaboration/dual_layer_context.py +128 -0
  40. scripts/collaboration/enhanced_worker.py +539 -0
  41. scripts/collaboration/feature_usage_tracker.py +206 -0
  42. scripts/collaboration/five_axis_consensus.py +334 -0
  43. scripts/collaboration/input_validator.py +401 -0
  44. scripts/collaboration/integration_example.py +287 -0
  45. scripts/collaboration/intent_workflow_mapper.py +350 -0
  46. scripts/collaboration/language_parsers.py +269 -0
  47. scripts/collaboration/lifecycle_protocol.py +1446 -0
  48. scripts/collaboration/llm_backend.py +453 -0
  49. scripts/collaboration/llm_cache.py +448 -0
  50. scripts/collaboration/llm_cache_async.py +347 -0
  51. scripts/collaboration/llm_retry.py +387 -0
  52. scripts/collaboration/llm_retry_async.py +389 -0
  53. scripts/collaboration/mce_adapter.py +597 -0
  54. scripts/collaboration/memory_bridge.py +1607 -0
  55. scripts/collaboration/models.py +537 -0
  56. scripts/collaboration/null_providers.py +297 -0
  57. scripts/collaboration/operation_classifier.py +289 -0
  58. scripts/collaboration/output_slicer.py +225 -0
  59. scripts/collaboration/performance_monitor.py +462 -0
  60. scripts/collaboration/permission_guard.py +865 -0
  61. scripts/collaboration/prompt_assembler.py +756 -0
  62. scripts/collaboration/prompt_variant_generator.py +483 -0
  63. scripts/collaboration/protocols.py +267 -0
  64. scripts/collaboration/report_formatter.py +352 -0
  65. scripts/collaboration/retrospective.py +279 -0
  66. scripts/collaboration/role_matcher.py +92 -0
  67. scripts/collaboration/role_template_market.py +352 -0
  68. scripts/collaboration/rule_collector.py +678 -0
  69. scripts/collaboration/scratchpad.py +346 -0
  70. scripts/collaboration/skill_registry.py +151 -0
  71. scripts/collaboration/skillifier.py +878 -0
  72. scripts/collaboration/standardized_role_template.py +317 -0
  73. scripts/collaboration/task_completion_checker.py +237 -0
  74. scripts/collaboration/test_quality_guard.py +695 -0
  75. scripts/collaboration/unified_gate_engine.py +598 -0
  76. scripts/collaboration/usage_tracker.py +309 -0
  77. scripts/collaboration/user_friendly_error.py +176 -0
  78. scripts/collaboration/verification_gate.py +312 -0
  79. scripts/collaboration/warmup_manager.py +635 -0
  80. scripts/collaboration/worker.py +513 -0
  81. scripts/collaboration/workflow_engine.py +684 -0
  82. scripts/dashboard.py +1088 -0
  83. scripts/generate_benchmark_report.py +786 -0
  84. scripts/history_manager.py +604 -0
  85. scripts/mcp_server.py +289 -0
  86. skills/__init__.py +32 -0
  87. skills/dispatch/handler.py +52 -0
  88. skills/intent/handler.py +59 -0
  89. skills/registry.py +67 -0
  90. skills/retrospective/__init__.py +0 -0
  91. skills/retrospective/handler.py +125 -0
  92. skills/review/handler.py +356 -0
  93. skills/security/handler.py +454 -0
  94. skills/test/__init__.py +0 -0
  95. skills/test/handler.py +78 -0
@@ -0,0 +1,642 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ CLI Visual Enhancement Module for DevSquad V3.6.0
5
+
6
+ Provides rich visual output for lifecycle commands including:
7
+ - Colored progress bars
8
+ - Phase status icons
9
+ - Percentage displays
10
+ - Gate status visualization
11
+ - Beautiful formatted tables
12
+
13
+ Usage:
14
+ from scripts.cli.cli_visual import VisualFormatter
15
+
16
+ vf = VisualFormatter()
17
+ vf.print_lifecycle_header(command, mapping, preset)
18
+ vf.print_phase_progress(phases, current_phase)
19
+ vf.print_gate_status(gate_result)
20
+ """
21
+
22
+ import sys
23
+ from typing import Any, Dict, List, Optional
24
+
25
+
26
+ class Colors:
27
+ """ANSI color codes for terminal output."""
28
+ RESET = '\033[0m'
29
+ BOLD = '\033[1m'
30
+ DIM = '\033[2m'
31
+
32
+ # Foreground colors
33
+ BLACK = '\033[30m'
34
+ RED = '\033[31m'
35
+ GREEN = '\033[32m'
36
+ YELLOW = '\033[33m'
37
+ BLUE = '\033[34m'
38
+ MAGENTA = '\033[35m'
39
+ CYAN = '\033[36m'
40
+ WHITE = '\033[37m'
41
+
42
+ # Background colors
43
+ BG_RED = '\033[41m'
44
+ BG_GREEN = '\033[42m'
45
+ BG_YELLOW = '\033[43m'
46
+ BG_BLUE = '\033[44m'
47
+
48
+
49
+ class Icons:
50
+ """Unicode icons for visual enhancement."""
51
+ # Phase states
52
+ CHECK = '✅'
53
+ CROSS = '❌'
54
+ ARROW_RIGHT = '▶'
55
+ CIRCLE = '⭕'
56
+ SKIP = '⏭️'
57
+ BLOCKED = '🚫'
58
+ RUNNING = '🔄'
59
+
60
+ # Status
61
+ SUCCESS = '✓'
62
+ FAIL = '✗'
63
+ WARNING = '⚠'
64
+ INFO = 'ℹ'
65
+
66
+ # Objects
67
+ FILE = '📄'
68
+ FOLDER = '📁'
69
+ GEAR = '⚙️'
70
+ ROCKET = '🚀'
71
+ CHART = '📊'
72
+ LOCK = '🔒'
73
+ KEY = '🔑'
74
+
75
+ # People
76
+ USER = '👤'
77
+ USERS = '👥'
78
+ ROBOT = '🤖'
79
+
80
+ # Misc
81
+ STAR = '★'
82
+ SPARKLE = '✨'
83
+ FIRE = '🔥'
84
+ BULB = '💡'
85
+ TARGET = '🎯'
86
+ FLAG = '🚩'
87
+
88
+
89
+ class ProgressBar:
90
+ """Animated progress bar for terminal output."""
91
+
92
+ def __init__(
93
+ self,
94
+ total: int = 100,
95
+ width: int = 40,
96
+ fill_char: str = '█',
97
+ empty_char: str = '░',
98
+ prefix: str = '',
99
+ suffix: str = '',
100
+ ):
101
+ self.total = total
102
+ self.width = width
103
+ self.fill_char = fill_char
104
+ self.empty_char = empty_char
105
+ self.prefix = prefix
106
+ self.suffix = suffix
107
+
108
+ def render(self, current: int) -> str:
109
+ """Render progress bar at given position."""
110
+ if self.total == 0:
111
+ percent = 100
112
+ else:
113
+ percent = int(current / self.total * 100)
114
+
115
+ filled = int(self.width * current / self.total)
116
+ bar = self.fill_char * filled + self.empty_char * (self.width - filled)
117
+
118
+ # Color based on percentage
119
+ if percent >= 80:
120
+ color = Colors.GREEN
121
+ elif percent >= 50:
122
+ color = Colors.YELLOW
123
+ elif percent >= 25:
124
+ color = Colors.CYAN
125
+ else:
126
+ color = Colors.RED
127
+
128
+ return f"{color}{self.prefix}[{bar}]{Colors.RESET}{self.suffix} {percent}%"
129
+
130
+ @staticmethod
131
+ def simple(current: int, total: int, width: int = 20) -> str:
132
+ """Quick static progress bar."""
133
+ if total == 0:
134
+ return f"[{'█' * width}] 100%"
135
+
136
+ percent = int(current / total * 100)
137
+ filled = int(width * current / total)
138
+ bar = '█' * filled + '░' * (width - filled)
139
+ return f"[{bar}] {percent}%"
140
+
141
+
142
+ class VisualFormatter:
143
+ """
144
+ Main formatter class for CLI visual enhancement.
145
+
146
+ Provides methods to format and display lifecycle information
147
+ in a visually appealing way.
148
+ """
149
+
150
+ def __init__(self, use_color: bool = True):
151
+ self.use_color = use_color
152
+ self.icons = Icons()
153
+ self.colors = Colors()
154
+
155
+ def _c(self, text: str, color: str) -> str:
156
+ """Apply color to text (if enabled)."""
157
+ if self.use_color:
158
+ return f"{color}{text}{self.colors.RESET}"
159
+ return text
160
+
161
+ def print_separator(
162
+ self,
163
+ char: str = '=',
164
+ length: int = 60,
165
+ color: Optional[str] = None,
166
+ ) -> None:
167
+ """Print a separator line."""
168
+ line = char * length
169
+ if color:
170
+ print(self._c(line, color))
171
+ else:
172
+ print(line)
173
+
174
+ def print_title(self, title: str, subtitle: str = '') -> None:
175
+ """Print a formatted title."""
176
+ self.print_separator('=', 60, Colors.CYAN)
177
+
178
+ main = self._c(f" {title}", Colors.BOLD + Colors.CYAN)
179
+ print(main)
180
+
181
+ if subtitle:
182
+ sub = self._c(f" {subtitle}", Colors.DIM)
183
+ print(sub)
184
+
185
+ self.print_separator('=', 60, Colors.CYAN)
186
+ print()
187
+
188
+ def print_lifecycle_header(
189
+ self,
190
+ command: str,
191
+ mapping: Optional[Any] = None,
192
+ preset: Optional[Dict] = None,
193
+ ) -> None:
194
+ """Print enhanced lifecycle command header."""
195
+ self.print_title(
196
+ f"🔄 DevSquad Lifecycle [{command.upper()}]",
197
+ "View Layer Mode (Plan C Architecture)"
198
+ )
199
+
200
+ # Command info box
201
+ print(self._c(" ┌─────────────────────────────────────────┐", Colors.CYAN))
202
+ print(self._c(" │", Colors.CYAN) +
203
+ f" 📌 Command: ".ljust(15) +
204
+ self._c(command.upper(), Colors.BOLD + Colors.YELLOW))
205
+ print(self._c(" │", Colors.CYAN))
206
+
207
+ if mapping:
208
+ phases_str = ', '.join(mapping.phases[:4])
209
+ if len(mapping.phases) > 4:
210
+ phases_str += f" (+{len(mapping.phases)-4} more)"
211
+
212
+ print(self._c(" │", Colors.CYAN) +
213
+ f" 📋 Phases: ".ljust(15) +
214
+ self._c(phases_str, Colors.GREEN))
215
+
216
+ if preset:
217
+ roles_str = ', '.join(preset.get('required_roles', [])[:3])
218
+ print(self._c(" │", Colors.CYAN) +
219
+ f" 👥 Roles: ".ljust(15) +
220
+ self._c(roles_str, Colors.BLUE))
221
+
222
+ mode = preset.get('mode', 'unknown')
223
+ gate = preset.get('gate', 'unknown')
224
+ print(self._c(" │", Colors.CYAN) +
225
+ f" ⚙️ Mode: ".ljust(15) +
226
+ self._c(mode, Colors.MAGENTA) +
227
+ " | ".ljust(5) +
228
+ f"🚧 Gate: {gate}")
229
+
230
+ print(self._c(" └─────────────────────────────────────────┘", Colors.CYAN))
231
+ print()
232
+
233
+ def print_phase_list(
234
+ self,
235
+ phases: List[Any],
236
+ current_phase: Optional[str] = None,
237
+ completed_phases: Optional[List[str]] = None,
238
+ ) -> None:
239
+ """Print formatted phase list with status icons."""
240
+ completed_phases = completed_phases or []
241
+
242
+ print(self._c(" 📋 Lifecycle Phases:", Colors.BOLD))
243
+ print()
244
+
245
+ for i, phase in enumerate(phases, 1):
246
+ phase_id = getattr(phase, 'phase_id', str(phase))
247
+ name = getattr(phase, 'name', phase_id)
248
+ optional = getattr(phase, 'optional', False)
249
+
250
+ # Determine status icon and color
251
+ if phase_id in completed_phases:
252
+ icon = Icons.CHECK
253
+ color = Colors.GREEN
254
+ status_text = "COMPLETED"
255
+ elif phase_id == current_phase:
256
+ icon = Icons.ARROW_RIGHT
257
+ color = Colors.YELLOW
258
+ status_text = "RUNNING"
259
+ elif optional:
260
+ icon = Icons.SKIP
261
+ color = Colors.DIM
262
+ status_text = "OPTIONAL"
263
+ else:
264
+ icon = Icons.CIRCLE
265
+ color = Colors.DIM
266
+ status_text = "PENDING"
267
+
268
+ # Format line
269
+ num = self._c(f"{i:2}.", Colors.DIM)
270
+ pid = self._c(f"[{phase_id}]", color)
271
+ pname = self._c(name.ljust(25), color if phase_id == current_phase else '')
272
+ picon = f" {icon}"
273
+ pstatus = self._c(f"<{status_text}>", Colors.DIM)
274
+
275
+ opt_tag = ""
276
+ if optional:
277
+ opt_tag = self._c(" [opt]", Colors.DIM)
278
+
279
+ print(f" {num} {pid} {pname}{picon}{pstatus}{opt_tag}")
280
+
281
+ print()
282
+
283
+ def print_progress_overview(
284
+ self,
285
+ current: int,
286
+ total: int,
287
+ label: str = "Progress",
288
+ ) -> None:
289
+ """Print progress overview with bar and stats."""
290
+ percent = int(current / total * 100) if total > 0 else 0
291
+
292
+ print(self._c(f" {Icons.CHART} {label}:", Colors.BOLD))
293
+ print()
294
+
295
+ # Progress bar
296
+ bar = ProgressBar.simple(current, total, 35)
297
+ colored_bar = self._colorize_bar(bar, percent)
298
+ print(f" {colored_bar}")
299
+ print()
300
+
301
+ # Stats
302
+ stats_line = (
303
+ f" {Icons.CHECK} Completed: "
304
+ f"{self._c(str(current), Colors.GREEN)} / "
305
+ f"{self._c(str(total), Colors.WHITE)} "
306
+ f"({self._c(f'{percent}%', Colors.BOLD)})"
307
+ )
308
+ print(stats_line)
309
+ print()
310
+
311
+ def _colorize_bar(self, bar: str, percent: int) -> str:
312
+ """Colorize progress bar based on percentage."""
313
+ if percent >= 80:
314
+ return self._c(bar, Colors.GREEN)
315
+ elif percent >= 50:
316
+ return self._c(bar, Colors.YELLOW)
317
+ elif percent >= 25:
318
+ return self._c(bar, Colors.CYAN)
319
+ else:
320
+ return self._c(bar, Colors.RED)
321
+
322
+ def print_gate_status(
323
+ self,
324
+ gate_result: Optional[Any] = None,
325
+ gate_type: str = "Phase",
326
+ ) -> None:
327
+ """Print gate check result with visual indicators."""
328
+ print(self._c(f" {Icons.LOCK} {gate_type} Gate Status:", Colors.BOLD))
329
+ print()
330
+
331
+ if gate_result is None:
332
+ print(f" {self._c(Icons.INFO, Colors.BLUE)} No gate result available")
333
+ print()
334
+ return
335
+
336
+ passed = getattr(gate_result, 'passed', False)
337
+ verdict = getattr(gate_result, 'verdict', 'UNKNOWN')
338
+ checks_run = getattr(gate_result, 'checks_run', 0)
339
+ checks_passed = getattr(gate_result, 'checks_passed', 0)
340
+
341
+ # Verdict display
342
+ if verdict.upper() == 'APPROVE':
343
+ verdict_icon = Icons.CHECK
344
+ verdict_color = Colors.GREEN
345
+ verdict_text = "APPROVED"
346
+ elif verdict.upper() == 'REJECT':
347
+ verdict_icon = Icons.CROSS
348
+ verdict_color = Colors.RED
349
+ verdict_text = "REJECTED"
350
+ elif verdict.upper() == 'CONDITIONAL':
351
+ verdict_icon = Icons.WARNING
352
+ verdict_color = Colors.YELLOW
353
+ verdict_text = "CONDITIONAL"
354
+ else:
355
+ verdict_icon = Icons.INFO
356
+ verdict_color = Colors.BLUE
357
+ verdict_text = verdict.upper()
358
+
359
+ verdict_line = (
360
+ f" {self._c(verdict_icon, verdict_color)} "
361
+ f"Verdict: "
362
+ f"{self._c(verdict_text, Colors.BOLD + verdict_color)}"
363
+ )
364
+ print(verdict_line)
365
+
366
+ # Checks summary
367
+ if checks_run > 0:
368
+ check_percent = int(checks_passed / checks_run * 100)
369
+ check_line = (
370
+ f" {Icons.GEAR} Checks: "
371
+ f"{self._c(str(checks_passed), Colors.GREEN)}/"
372
+ f"{self._c(str(checks_run), Colors.WHITE)} "
373
+ f"({check_percent}%)"
374
+ )
375
+ print(check_line)
376
+
377
+ # Issues summary
378
+ critical_issues = getattr(gate_result, 'critical_issues', [])
379
+ warnings = getattr(gate_result, 'warnings', [])
380
+ evidence_required = getattr(gate_result, 'evidence_required', [])
381
+
382
+ if critical_issues:
383
+ print(f"\n {self._c(Icons.CROSS + ' Critical Issues:', Colors.RED)}")
384
+ for issue in critical_issues[:3]:
385
+ msg = issue.get('message', str(issue))[:60]
386
+ print(f" {self._c('•', Colors.RED)} {msg}")
387
+ if len(critical_issues) > 3:
388
+ print(f" ... and {len(critical_issues)-3} more")
389
+
390
+ if warnings:
391
+ print(f"\n {self._c(Icons.WARNING + ' Warnings:', Colors.YELLOW)}")
392
+ for warning in warnings[:3]:
393
+ msg = warning.get('message', str(warning))[:60]
394
+ print(f" {self._c('•', Colors.YELLOW)} {msg}")
395
+ if len(warnings) > 3:
396
+ print(f" ... and {len(warnings)-3} more")
397
+
398
+ if evidence_required:
399
+ print(f"\n {self._c(Icons.KEY + ' Evidence Required:', Colors.CYAN)}")
400
+ for ev in evidence_required[:5]:
401
+ print(f" {self._c('•', Colors.CYAN)} {ev}")
402
+
403
+ print()
404
+
405
+ def print_status_summary(
406
+ self,
407
+ status: Any,
408
+ ) -> None:
409
+ """Print comprehensive status summary."""
410
+ mode = getattr(status, 'mode', None)
411
+ current_phase = getattr(status, 'current_phase', None)
412
+ completed = getattr(status, 'completed_phases', [])
413
+ failed = getattr(status, 'failed_phases', [])
414
+ blocked = getattr(status, 'blocked_phases', [])
415
+ progress = getattr(status, 'progress_percent', 0)
416
+ can_advance = getattr(status, 'can_advance', True)
417
+ next_phase = getattr(status, 'next_phase', None)
418
+
419
+ self.print_title(
420
+ f"📊 Lifecycle Status Summary",
421
+ f"Mode: {mode.value if hasattr(mode, 'value') else mode}" if mode else ''
422
+ )
423
+
424
+ # Overview stats
425
+ print(self._c(" ┌─ Overview ─────────────────────────────┐", Colors.CYAN))
426
+ print(self._c(" │", Colors.CYAN))
427
+
428
+ mode_str = mode.value if hasattr(mode, 'value') else str(mode)
429
+ print(self._c(" │", Colors.CYAN) +
430
+ f" Mode: ".ljust(12) +
431
+ self._c(mode_str, Colors.BOLD + Colors.MAGENTA))
432
+
433
+ progress_str = f"{progress:.1f}%"
434
+ print(self._c(" │", Colors.CYAN) +
435
+ f" Progress: ".ljust(12) +
436
+ self._c(progress_str, Colors.BOLD + self._progress_color(progress)))
437
+
438
+ can_advance_str = "Yes ✅" if can_advance else "No ❌"
439
+ print(self._c(" │", Colors.CYAN) +
440
+ f" Can Advance: ".ljust(12) +
441
+ self._c(can_advance_str, Colors.GREEN if can_advance else Colors.RED))
442
+
443
+ print(self._c(" └────────────────────────────────────────┘", Colors.CYAN))
444
+ print()
445
+
446
+ # Phase counts
447
+ total_phases = len(completed) + len(failed) + len(blocked)
448
+ print(f" {Icons.CHART} Phase Statistics:")
449
+ print(f" {Icons.CHECK} Completed: {self._c(str(len(completed)), Colors.GREEN)}")
450
+ print(f" {Icons.CROSS} Failed: {self._c(str(len(failed)), Colors.RED)}")
451
+ print(f" {Icons.BLOCKED} Blocked: {self._c(str(len(blocked)), Colors.YELLOW)}")
452
+ print(f" {Icons.ARROW_RIGHT} Current: {current_phase or 'None'}")
453
+ print(f" {Icons.TARGET} Next: {next_phase or 'N/A'}")
454
+ print()
455
+
456
+ def _progress_color(self, percent: float) -> str:
457
+ """Get color for progress percentage."""
458
+ if percent >= 80:
459
+ return Colors.GREEN
460
+ elif percent >= 50:
461
+ return Colors.YELLOW
462
+ elif percent >= 25:
463
+ return Colors.CYAN
464
+ else:
465
+ return Colors.RED
466
+
467
+ def print_footer(self, version: str = "V3.6.0") -> None:
468
+ """Print footer with version and timestamp."""
469
+ from datetime import datetime
470
+
471
+ self.print_separator('-', 40, Colors.DIM)
472
+
473
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
474
+ footer = (
475
+ f" DevSquad {version} | "
476
+ f"{timestamp} | "
477
+ f"{Icons.SPARKLE} Plan C Layered Architecture"
478
+ )
479
+ print(self._c(footer, Colors.DIM))
480
+ self.print_separator('-', 40, Colors.DIM)
481
+
482
+ def print_success_message(self, message: str = "Operation completed successfully!") -> None:
483
+ """Print success message with icon."""
484
+ print()
485
+ print(f" {self._c(Icons.CHECK + ' ' + message, Colors.GREEN + Colors.BOLD)}")
486
+ print()
487
+
488
+ def print_error_message(self, message: str) -> None:
489
+ """Print error message with icon."""
490
+ print()
491
+ print(f" {self._c(Icons.CROSS + ' Error: ' + message, Colors.RED + Colors.BOLD)}")
492
+ print()
493
+
494
+ def print_info_box(
495
+ self,
496
+ title: str,
497
+ content: List[str],
498
+ icon: str = Icons.INFO,
499
+ color: str = Colors.BLUE,
500
+ ) -> None:
501
+ """Print an info box with title and content."""
502
+ print(f"\n {self._c(icon + ' ' + title, color + Colors.BOLD)}")
503
+ print(f" {'─' * (len(title) + 4)}")
504
+ for line in content:
505
+ print(f" {self._c('•', color)} {line}")
506
+ print()
507
+
508
+
509
+ def get_visual_formatter(use_color: bool = True) -> VisualFormatter:
510
+ """Get a VisualFormatter instance (factory function)."""
511
+ return VisualFormatter(use_color=use_color)
512
+
513
+
514
+ def print_enhanced_lifecycle_command(
515
+ command: str,
516
+ task: str,
517
+ use_visual: bool = True,
518
+ ) -> int:
519
+ """
520
+ Print enhanced lifecycle command output.
521
+
522
+ This is the main entry point for visual CLI output.
523
+
524
+ Args:
525
+ command: Lifecycle command (spec/plan/build/test/review/ship)
526
+ task: Task description
527
+ use_visual: Whether to use visual formatting
528
+
529
+ Returns:
530
+ Exit code (0 for success)
531
+ """
532
+ if not use_visual:
533
+ return 0 # Let normal output proceed
534
+
535
+ try:
536
+ from scripts.collaboration.lifecycle_protocol import (
537
+ VIEW_MAPPINGS,
538
+ create_lifecycle_protocol,
539
+ LifecycleMode,
540
+ )
541
+
542
+ vf = VisualFormatter(use_color=True)
543
+
544
+ # Get mapping and protocol
545
+ mapping = VIEW_MAPPINGS.get(command)
546
+ protocol = create_lifecycle_protocol(LifecycleMode.SHORTCUT)
547
+ preset = _get_preset(command)
548
+
549
+ # Print enhanced header
550
+ vf.print_lifecycle_header(command, mapping, preset)
551
+
552
+ # Show resolved phases
553
+ if mapping:
554
+ phases = protocol.resolve_command_to_phases(command)
555
+ if phases:
556
+ vf.print_phase_list(phases)
557
+
558
+ # Show progress placeholder
559
+ vf.print_progress_overview(0, len(phases), "Command Coverage")
560
+
561
+ # Show gate info
562
+ gate_name = preset.get('gate', 'Unknown') if preset else 'Unknown'
563
+ vf.print_gate_status(None, gate_name)
564
+
565
+ # Print next steps
566
+ vf.print_info_box(
567
+ "Next Steps",
568
+ [
569
+ f"Run: python3 scripts/cli.py dispatch -t \"{task}\" --roles architect solo-coder",
570
+ f"Or use: python3 examples/quick_start.py",
571
+ f"View guide: cat docs/USAGE_GUIDE.md",
572
+ ],
573
+ icon=Icons.ROCKET,
574
+ color=Colors.GREEN,
575
+ )
576
+
577
+ vf.print_footer()
578
+ vf.print_success_message("Ready to execute!")
579
+
580
+ return 0
581
+
582
+ except Exception as e:
583
+ print(f"\nVisual enhancement error: {e}\n")
584
+ return 0 # Don't block normal operation
585
+
586
+
587
+ def _get_preset(command: str) -> Optional[Dict]:
588
+ """Get preset configuration for a command."""
589
+ presets = {
590
+ "spec": {
591
+ "description": "Define and refine requirements before implementation",
592
+ "required_roles": ["architect", "product-manager"],
593
+ "mode": "sequential",
594
+ "gate": "spec_first",
595
+ },
596
+ "plan": {
597
+ "description": "Break down work into small, verifiable tasks",
598
+ "required_roles": ["architect", "product-manager"],
599
+ "mode": "auto",
600
+ "gate": "task_breakdown_complete",
601
+ },
602
+ "build": {
603
+ "description": "Implement incrementally with TDD discipline",
604
+ "required_roles": ["architect", "solo-coder", "tester"],
605
+ "mode": "parallel",
606
+ "gate": "incremental_verification",
607
+ },
608
+ "test": {
609
+ "description": "Run tests with mandatory evidence requirements",
610
+ "required_roles": ["tester", "solo-coder"],
611
+ "mode": "consensus",
612
+ "gate": "evidence_required",
613
+ },
614
+ "review": {
615
+ "description": "Five-axis code review (correctness/readability/arch/security/performance)",
616
+ "required_roles": ["solo-coder", "security", "tester", "architect"],
617
+ "mode": "consensus",
618
+ "gate": "change_size_limit",
619
+ },
620
+ "ship": {
621
+ "description": "Pre-launch verification and deployment preparation",
622
+ "required_roles": ["devops", "security", "architect"],
623
+ "mode": "sequential",
624
+ "gate": "pre_launch_checklist",
625
+ },
626
+ }
627
+ return presets.get(command)
628
+
629
+
630
+ if __name__ == "__main__":
631
+ # Quick demo of visual formatter
632
+ vf = VisualFormatter()
633
+
634
+ vf.print_title("Visual Formatter Demo", "Testing all features")
635
+
636
+ # Demo progress bars
637
+ for i in [0, 25, 50, 75, 100]:
638
+ bar = ProgressBar.simple(i, 100, 30)
639
+ print(f" {vf._colorize_bar(bar, i)}")
640
+
641
+ print()
642
+ vf.print_success_message("Demo complete!")