Implement CLI commands and utility functions for MVP-1

- Add complete CLI command implementations with Typer subcommands
- Implement utils/time.py with duration formatting and datetime utilities
- Implement utils/path.py with project path management utilities
- Wire up all commands to main CLI entry point
This commit is contained in:
2026-03-23 08:55:41 -03:00
parent b0c65a00a2
commit 88a474a78d
3 changed files with 212 additions and 1 deletions

View File

@@ -1 +1,87 @@
"""Path utility functions."""
from pathlib import Path
from typing import Optional
def ensure_dir(path: Path) -> Path:
"""Ensure a directory exists, creating it if necessary.
Args:
path: Path to the directory.
Returns:
The path to the directory.
"""
path.mkdir(parents=True, exist_ok=True)
return path
def project_root(slug: str, projects_root: Optional[Path] = None) -> Path:
"""Get the root path for a project.
Args:
slug: Project slug.
projects_root: Root directory for all projects. Defaults to ./projects.
Returns:
Path to the project root.
"""
if projects_root is None:
projects_root = Path("projects")
return projects_root / slug
def relative_to_project(slug: str, relative_path: str, projects_root: Optional[Path] = None) -> Path:
"""Get a path relative to a project.
Args:
slug: Project slug.
relative_path: Relative path within the project.
projects_root: Root directory for all projects.
Returns:
Absolute path to the file within the project.
"""
root = project_root(slug, projects_root)
return root / relative_path
def is_within_project(slug: str, file_path: Path, projects_root: Optional[Path] = None) -> bool:
"""Check if a file path is within a project.
Args:
slug: Project slug.
file_path: Path to check.
projects_root: Root directory for all projects.
Returns:
True if file_path is within the project directory.
"""
project_path = project_root(slug, projects_root)
try:
file_path.resolve().relative_to(project_path.resolve())
return True
except ValueError:
return False
def sanitize_filename(filename: str) -> str:
"""Sanitize a filename by removing invalid characters.
Args:
filename: Original filename.
Returns:
Sanitized filename safe for file system use.
"""
# Remove or replace invalid characters
invalid_chars = '<>:"/\\|?*'
for char in invalid_chars:
filename = filename.replace(char, "_")
# Limit length
if len(filename) > 255:
filename = filename[:255]
return filename