Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Thank you for your interest in contributing!
## Development Setup

1. Fork the repository
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/revenueholdings.git`
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/devforge-cli.git`
3. Create a virtual environment: `python -m venv venv`
4. Install dev dependencies: `pip install -e ".[dev]"`

Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Generated by Agent B — Lint & Type Scripts
.PHONY: lint test format typecheck format-check
.PHONY: lint test format typecheck format-check clean

lint:
ruff check src/ tests/
Expand All @@ -15,3 +15,7 @@ typecheck:

test:
pytest -q

clean:
rm -rf build/ dist/ *.egg-info/ .pytest_cache/ __pycache__/
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
27 changes: 23 additions & 4 deletions src/devforge/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""DevForge unified CLI entry point."""

import builtins as _builtins
import subprocess
import sys
import typer
Expand Down Expand Up @@ -86,7 +85,7 @@ def install(
):
"""Install a DevForge tool."""
if tool == "all":
targets = _builtins.list(TOOLS.keys())
targets = list(TOOLS.keys())
extras = ",".join(TOOLS.keys())
elif tool in TOOLS:
targets = [tool]
Expand Down Expand Up @@ -119,7 +118,7 @@ def show_versions(
console.print(f"[red]Unknown tool: {tool}[/red]")
console.print(f"Available: {', '.join(TOOLS.keys())}")
raise typer.Exit(code=1)
targets = [tool] if tool else _builtins.list(TOOLS.keys())
targets = [tool] if tool else list(TOOLS.keys())

for t in targets:
info = TOOLS[t]
Expand Down Expand Up @@ -156,15 +155,35 @@ def dispatch(
try:
result = subprocess.run(
[sys.executable, "-m", info["package"].replace("-", "_")] + (args or []),
capture_output=False,
capture_output=True,
text=True,
)
if result.returncode == 0:
sys.stdout.write(result.stdout)
if result.stderr:
sys.stderr.write(result.stderr)
sys.exit(0)
# Module not found — show friendly install message
if "No module named" in result.stderr:
console.print(
f"[red]Tool '{tool_name}' not installed.[/red]\n"
f"Install with: [green]pip install devforge[{tool_name}][/green]"
)
raise typer.Exit(code=1) from None
# Tool ran but failed — show its output and propagate exit code
sys.stdout.write(result.stdout)
sys.stderr.write(result.stderr)
sys.exit(result.returncode)
except FileNotFoundError:
# Only reached if sys.executable itself is missing (extremely rare)
console.print(
f"[red]Tool '{tool_name}' not installed.[/red]\n"
f"Install with: [green]pip install devforge-tools[{tool_name}][/green]"
)
raise typer.Exit(code=1) from None
except Exception as e:
console.print(f"[red]Unexpected error running '{tool_name}': {e}[/red]")
raise typer.Exit(code=1) from e

dispatch.__name__ = tool_name
dispatch.__doc__ = f"Run `{pkg}` commands via the {tool_name} subcommand."
Expand Down