Return the project root if it is a spec-kit project, else exit. Honors the ``SPECIFY_INIT_DIR`` override (same validation rules as the shell scripts) so a member project can be targeted from a monorepo root without ``cd``. This is the resolution chokepoint for *every* project-scoped
()
| 517 | |
| 518 | |
| 519 | def _require_specify_project() -> Path: |
| 520 | """Return the project root if it is a spec-kit project, else exit. |
| 521 | |
| 522 | Honors the ``SPECIFY_INIT_DIR`` override (same validation rules as the shell |
| 523 | scripts) so a member project can be targeted from a monorepo root without |
| 524 | ``cd``. This is the resolution chokepoint for *every* project-scoped |
| 525 | subcommand — ``integration``, ``extension``, ``workflow``, ``preset``, and the |
| 526 | rest that operate on an existing ``.specify/`` project — so the override |
| 527 | applies to all of them uniformly. When the override is unset, the project is |
| 528 | the current directory, as before. |
| 529 | """ |
| 530 | override = _resolve_init_dir_override() |
| 531 | if override is not None: |
| 532 | return override |
| 533 | project_root = Path.cwd() |
| 534 | if (project_root / ".specify").is_dir(): |
| 535 | return project_root |
| 536 | err_console.print("[red]Error:[/red] Not a Spec Kit project (no .specify/ directory)") |
| 537 | err_console.print( |
| 538 | "Run this command from a Spec Kit project root or set SPECIFY_INIT_DIR to one." |
| 539 | ) |
| 540 | raise typer.Exit(1) |
| 541 | |
| 542 | |
| 543 | # ===== Preset Commands ===== |
nothing calls this directly
no test coverage detected