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.
- galangal/__init__.py +8 -0
- galangal/__main__.py +6 -0
- galangal/ai/__init__.py +6 -0
- galangal/ai/base.py +55 -0
- galangal/ai/claude.py +278 -0
- galangal/ai/gemini.py +38 -0
- galangal/cli.py +296 -0
- galangal/commands/__init__.py +42 -0
- galangal/commands/approve.py +187 -0
- galangal/commands/complete.py +268 -0
- galangal/commands/init.py +173 -0
- galangal/commands/list.py +20 -0
- galangal/commands/pause.py +40 -0
- galangal/commands/prompts.py +98 -0
- galangal/commands/reset.py +43 -0
- galangal/commands/resume.py +29 -0
- galangal/commands/skip.py +216 -0
- galangal/commands/start.py +144 -0
- galangal/commands/status.py +62 -0
- galangal/commands/switch.py +28 -0
- galangal/config/__init__.py +13 -0
- galangal/config/defaults.py +133 -0
- galangal/config/loader.py +113 -0
- galangal/config/schema.py +155 -0
- galangal/core/__init__.py +18 -0
- galangal/core/artifacts.py +66 -0
- galangal/core/state.py +248 -0
- galangal/core/tasks.py +170 -0
- galangal/core/workflow.py +835 -0
- galangal/prompts/__init__.py +5 -0
- galangal/prompts/builder.py +166 -0
- galangal/prompts/defaults/design.md +54 -0
- galangal/prompts/defaults/dev.md +39 -0
- galangal/prompts/defaults/docs.md +46 -0
- galangal/prompts/defaults/pm.md +75 -0
- galangal/prompts/defaults/qa.md +49 -0
- galangal/prompts/defaults/review.md +65 -0
- galangal/prompts/defaults/security.md +68 -0
- galangal/prompts/defaults/test.md +59 -0
- galangal/ui/__init__.py +5 -0
- galangal/ui/console.py +123 -0
- galangal/ui/tui.py +1065 -0
- galangal/validation/__init__.py +5 -0
- galangal/validation/runner.py +395 -0
- galangal_orchestrate-0.2.11.dist-info/METADATA +278 -0
- galangal_orchestrate-0.2.11.dist-info/RECORD +49 -0
- galangal_orchestrate-0.2.11.dist-info/WHEEL +4 -0
- galangal_orchestrate-0.2.11.dist-info/entry_points.txt +2 -0
- 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
|