#!/usr/bin/env python3 """Check tasks prerequisites and resolve the tasks template.""" from __future__ import annotations import json import sys from pathlib import Path try: from common import ( FeaturePaths, format_speckit_command, get_feature_paths, resolve_template, ) except ImportError: # pragma: no cover - direct execution from unusual cwd sys.path.insert(0, str(Path(__file__).resolve().parent)) from common import ( FeaturePaths, format_speckit_command, get_feature_paths, resolve_template, ) def _json_line(payload: object) -> str: return json.dumps(payload, ensure_ascii=False, separators=(",", ":")) + "\n" def _help_text(argv0: str) -> str: return f"""Usage: {argv0} [--json] --json Output results in JSON format --help Show this help message """ def _dir_has_entries(path: Path) -> bool: try: return path.is_dir() and any(path.iterdir()) except OSError: return False def _available_docs(paths: FeaturePaths) -> list[str]: docs: list[str] = [] if paths.research.is_file(): docs.append("research.md") if paths.data_model.is_file(): docs.append("data-model.md") if _dir_has_entries(paths.contracts_dir): docs.append("contracts/") if paths.quickstart.is_file(): docs.append("quickstart.md") return docs def _check_file(path: Path, description: str) -> None: marker = "✓" if path.is_file() else "✗" print(f" {marker} {description}") def _check_dir(path: Path, description: str) -> None: marker = "✓" if _dir_has_entries(path) else "✗" print(f" {marker} {description}") def main(argv: list[str] | None = None) -> int: json_mode = False for arg in list(argv if argv is not None else sys.argv[1:]): if arg == "--json": json_mode = True elif arg in {"--help", "-h"}: sys.stdout.write(_help_text(sys.argv[0])) return 0 else: print(f"ERROR: Unknown option '{arg}'", file=sys.stderr) return 1 try: paths = get_feature_paths(script_file=Path(__file__)) except SystemExit as exc: if exc.code == 0: return 0 print("ERROR: Failed to resolve feature paths", file=sys.stderr) return int(exc.code) if isinstance(exc.code, int) else 1 if not paths.impl_plan.is_file(): print(f"ERROR: plan.md not found in {paths.feature_dir}", file=sys.stderr) print( f"Run {format_speckit_command('plan', paths.repo_root)} first to create the implementation plan.", file=sys.stderr, ) return 1 if not paths.feature_spec.is_file(): print(f"ERROR: spec.md not found in {paths.feature_dir}", file=sys.stderr) print( f"Run {format_speckit_command('specify', paths.repo_root)} first to create the feature structure.", file=sys.stderr, ) return 1 docs = _available_docs(paths) tasks_template = resolve_template("tasks-template", paths.repo_root) if tasks_template is None or not tasks_template.is_file(): print( "ERROR: Could not resolve required tasks-template from the template " f"override stack for {paths.repo_root}", file=sys.stderr, ) print( "Template 'tasks-template' was not found in any supported location " "(overrides, presets, extensions, or shared core). Add an override at " ".specify/templates/overrides/tasks-template.md, or run 'specify init' " "/ reinstall shared infra to restore the core " ".specify/templates/tasks-template.md template.", file=sys.stderr, ) return 1 if json_mode: sys.stdout.write( _json_line( { "FEATURE_DIR": str(paths.feature_dir), "AVAILABLE_DOCS": docs, "TASKS_TEMPLATE": str(tasks_template), } ) ) else: print(f"FEATURE_DIR: {paths.feature_dir}") print(f"TASKS_TEMPLATE: {tasks_template}") print("AVAILABLE_DOCS:") _check_file(paths.research, "research.md") _check_file(paths.data_model, "data-model.md") _check_dir(paths.contracts_dir, "contracts/") _check_file(paths.quickstart, "quickstart.md") return 0 if __name__ == "__main__": raise SystemExit(main())