Skip to content

Commit 24bd3e5

Browse files
Ralph Agentclaude
andcommitted
feat: [US-008] - Implement full onboarding flow orchestrator
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 87b6e94 commit 24bd3e5

1 file changed

Lines changed: 95 additions & 1 deletion

File tree

onboard.py

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,94 @@ def _validate_kebab_case(value: str) -> bool | str:
3838
return True
3939

4040

41+
STEPS: list[tuple[str, str]] = [
42+
("Rename", "rename"),
43+
("Dependencies", "deps"),
44+
("Environment Variables", "env"),
45+
("Pre-commit Hooks", "hooks"),
46+
("Media Generation", "media"),
47+
]
48+
49+
STEP_FUNCTIONS: dict[str, object] = {}
50+
51+
52+
def _run_orchestrator() -> None:
53+
"""Run the full onboarding flow, executing all steps in sequence."""
54+
project_name = _read_pyproject_name()
55+
rprint(
56+
Panel(
57+
f"[bold]{project_name}[/bold]\n\n"
58+
"This wizard will guide you through:\n"
59+
" 1. Rename - Set project name and description\n"
60+
" 2. Dependencies - Install project dependencies\n"
61+
" 3. Environment - Configure API keys and secrets\n"
62+
" 4. Hooks - Activate pre-commit hooks\n"
63+
" 5. Media - Generate banner and logo assets",
64+
title="Welcome to Project Onboarding",
65+
border_style="blue",
66+
)
67+
)
68+
69+
total = len(STEPS)
70+
completed: list[str] = []
71+
skipped: list[str] = []
72+
73+
for i, (label, cmd_name) in enumerate(STEPS, 1):
74+
rprint(f"\n[bold cyan]--- Step {i}/{total}: {label} ---[/bold cyan]")
75+
answer = questionary.select(
76+
"Run this step?",
77+
choices=["Yes", "Skip"],
78+
default="Yes",
79+
).ask()
80+
if answer is None:
81+
raise typer.Abort()
82+
83+
if answer == "Skip":
84+
skipped.append(label)
85+
rprint(f"[yellow]- {label} skipped[/yellow]")
86+
continue
87+
88+
try:
89+
step_fn = STEP_FUNCTIONS[cmd_name]
90+
step_fn() # type: ignore[operator]
91+
completed.append(label)
92+
except (typer.Exit, SystemExit) as exc:
93+
code = getattr(exc, "code", getattr(exc, "exit_code", 1))
94+
if code and code != 0:
95+
rprint(f"[red]✗ {label} failed.[/red]")
96+
cont = questionary.confirm(
97+
"Continue with remaining steps?", default=True
98+
).ask()
99+
if cont is None or not cont:
100+
raise typer.Abort() from None
101+
skipped.append(f"{label} (failed)")
102+
else:
103+
completed.append(label)
104+
105+
_print_summary(completed, skipped)
106+
107+
108+
def _print_summary(completed: list[str], skipped: list[str]) -> None:
109+
"""Print the final onboarding summary."""
110+
lines: list[str] = []
111+
for name in completed:
112+
lines.append(f"[green]✓[/green] {name}")
113+
for name in skipped:
114+
lines.append(f"[yellow]-[/yellow] {name}")
115+
lines.append("")
116+
lines.append("[bold]Suggested next commands:[/bold]")
117+
lines.append(" make test - Run tests")
118+
lines.append(" make ci - Run CI checks")
119+
lines.append(" make all - Run main application")
120+
121+
rprint(Panel("\n".join(lines), title="Onboarding Summary", border_style="green"))
122+
123+
41124
@app.callback(invoke_without_command=True)
42125
def main(ctx: typer.Context) -> None:
43126
"""Run the full onboarding flow, or use a subcommand for a specific step."""
44127
if ctx.invoked_subcommand is None:
45-
rprint("[yellow]Full onboarding flow not yet implemented.[/yellow]")
128+
_run_orchestrator()
46129

47130

48131
@app.command()
@@ -441,5 +524,16 @@ def media() -> None:
441524
rprint(f" {f}")
442525

443526

527+
# Register step functions for the orchestrator
528+
STEP_FUNCTIONS.update(
529+
{
530+
"rename": rename,
531+
"deps": deps,
532+
"env": env,
533+
"hooks": hooks,
534+
"media": media,
535+
}
536+
)
537+
444538
if __name__ == "__main__":
445539
app()

0 commit comments

Comments
 (0)