galangal-orchestrate 0.2.11__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.

Potentially problematic release.


This version of galangal-orchestrate might be problematic. Click here for more details.

Files changed (49) hide show
  1. galangal/__init__.py +8 -0
  2. galangal/__main__.py +6 -0
  3. galangal/ai/__init__.py +6 -0
  4. galangal/ai/base.py +55 -0
  5. galangal/ai/claude.py +278 -0
  6. galangal/ai/gemini.py +38 -0
  7. galangal/cli.py +296 -0
  8. galangal/commands/__init__.py +42 -0
  9. galangal/commands/approve.py +187 -0
  10. galangal/commands/complete.py +268 -0
  11. galangal/commands/init.py +173 -0
  12. galangal/commands/list.py +20 -0
  13. galangal/commands/pause.py +40 -0
  14. galangal/commands/prompts.py +98 -0
  15. galangal/commands/reset.py +43 -0
  16. galangal/commands/resume.py +29 -0
  17. galangal/commands/skip.py +216 -0
  18. galangal/commands/start.py +144 -0
  19. galangal/commands/status.py +62 -0
  20. galangal/commands/switch.py +28 -0
  21. galangal/config/__init__.py +13 -0
  22. galangal/config/defaults.py +133 -0
  23. galangal/config/loader.py +113 -0
  24. galangal/config/schema.py +155 -0
  25. galangal/core/__init__.py +18 -0
  26. galangal/core/artifacts.py +66 -0
  27. galangal/core/state.py +248 -0
  28. galangal/core/tasks.py +170 -0
  29. galangal/core/workflow.py +835 -0
  30. galangal/prompts/__init__.py +5 -0
  31. galangal/prompts/builder.py +166 -0
  32. galangal/prompts/defaults/design.md +54 -0
  33. galangal/prompts/defaults/dev.md +39 -0
  34. galangal/prompts/defaults/docs.md +46 -0
  35. galangal/prompts/defaults/pm.md +75 -0
  36. galangal/prompts/defaults/qa.md +49 -0
  37. galangal/prompts/defaults/review.md +65 -0
  38. galangal/prompts/defaults/security.md +68 -0
  39. galangal/prompts/defaults/test.md +59 -0
  40. galangal/ui/__init__.py +5 -0
  41. galangal/ui/console.py +123 -0
  42. galangal/ui/tui.py +1065 -0
  43. galangal/validation/__init__.py +5 -0
  44. galangal/validation/runner.py +395 -0
  45. galangal_orchestrate-0.2.11.dist-info/METADATA +278 -0
  46. galangal_orchestrate-0.2.11.dist-info/RECORD +49 -0
  47. galangal_orchestrate-0.2.11.dist-info/WHEEL +4 -0
  48. galangal_orchestrate-0.2.11.dist-info/entry_points.txt +2 -0
  49. galangal_orchestrate-0.2.11.dist-info/licenses/LICENSE +674 -0
galangal/ui/console.py ADDED
@@ -0,0 +1,123 @@
1
+ """
2
+ Console output utilities using Rich.
3
+ """
4
+
5
+ from rich.console import Console
6
+ from rich.table import Table
7
+ from rich.panel import Panel
8
+
9
+ from galangal.core.state import Stage, TaskType, TASK_TYPE_SKIP_STAGES
10
+
11
+ console = Console()
12
+
13
+
14
+ def print_success(message: str) -> None:
15
+ """Print a success message."""
16
+ console.print(f"[green]✓ {message}[/green]")
17
+
18
+
19
+ def print_error(message: str) -> None:
20
+ """Print an error message."""
21
+ console.print(f"[red]✗ {message}[/red]")
22
+
23
+
24
+ def print_warning(message: str) -> None:
25
+ """Print a warning message."""
26
+ console.print(f"[yellow]⚠ {message}[/yellow]")
27
+
28
+
29
+ def print_info(message: str) -> None:
30
+ """Print an info message."""
31
+ console.print(f"[blue]ℹ {message}[/blue]")
32
+
33
+
34
+ def display_task_list(
35
+ tasks: list[tuple[str, str, str, str]], active: str | None
36
+ ) -> None:
37
+ """Display a table of tasks."""
38
+ if not tasks:
39
+ print_info("No tasks found.")
40
+ return
41
+
42
+ table = Table(title="Tasks")
43
+ table.add_column("", style="cyan", width=2)
44
+ table.add_column("Name", style="bold")
45
+ table.add_column("Stage")
46
+ table.add_column("Type")
47
+ table.add_column("Description")
48
+
49
+ for name, stage, task_type, desc in tasks:
50
+ marker = "→" if name == active else ""
51
+ stage_style = "green" if stage == "COMPLETE" else "yellow"
52
+ table.add_row(
53
+ marker,
54
+ name,
55
+ f"[{stage_style}]{stage}[/{stage_style}]",
56
+ task_type,
57
+ desc,
58
+ )
59
+
60
+ console.print(table)
61
+
62
+
63
+ def display_status(
64
+ task_name: str,
65
+ stage: Stage,
66
+ task_type: TaskType,
67
+ attempt: int,
68
+ awaiting_approval: bool,
69
+ last_failure: str | None,
70
+ description: str,
71
+ artifacts: list[tuple[str, bool]],
72
+ ) -> None:
73
+ """Display detailed task status."""
74
+ status_color = "green" if stage == Stage.COMPLETE else "yellow"
75
+
76
+ console.print(Panel(f"[bold]{task_name}[/bold]", title="Task Status"))
77
+ console.print(f"[dim]Stage:[/dim] [{status_color}]{stage.value}[/{status_color}]")
78
+ console.print(f"[dim]Type:[/dim] {task_type.display_name()}")
79
+ console.print(f"[dim]Attempt:[/dim] {attempt}")
80
+ console.print(f"[dim]Description:[/dim] {description[:100]}...")
81
+
82
+ if awaiting_approval:
83
+ console.print("[yellow]⏳ Awaiting approval[/yellow]")
84
+
85
+ if last_failure:
86
+ console.print(f"[red]Last failure:[/red] {last_failure[:200]}...")
87
+
88
+ # Artifacts
89
+ console.print("\n[bold]Artifacts:[/bold]")
90
+ for name, exists in artifacts:
91
+ icon = "✓" if exists else "○"
92
+ color = "green" if exists else "dim"
93
+ console.print(f" [{color}]{icon} {name}[/{color}]")
94
+
95
+
96
+ def display_task_type_menu() -> None:
97
+ """Display the task type selection menu."""
98
+ console.print("\n[bold]Select task type:[/bold]")
99
+ for i, task_type in enumerate(TaskType, 1):
100
+ skipped = TASK_TYPE_SKIP_STAGES.get(task_type, set())
101
+ skip_info = f" [dim](skips: {', '.join(s.value for s in skipped)})[/dim]" if skipped else ""
102
+ console.print(f" [{i}] {task_type.display_name()} - {task_type.description()}{skip_info}")
103
+
104
+
105
+ def get_task_type_from_input(choice: str) -> TaskType | None:
106
+ """Convert user input to TaskType."""
107
+ task_types = list(TaskType)
108
+
109
+ # Try numeric selection
110
+ try:
111
+ idx = int(choice) - 1
112
+ if 0 <= idx < len(task_types):
113
+ return task_types[idx]
114
+ except ValueError:
115
+ pass
116
+
117
+ # Try name match
118
+ choice_lower = choice.lower().replace(" ", "_").replace("-", "_")
119
+ for tt in TaskType:
120
+ if tt.value == choice_lower or tt.display_name().lower() == choice.lower():
121
+ return tt
122
+
123
+ return None