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
3 changes: 1 addition & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
DevForge CLI meta-package that installs all 11 developer tools in one command. Provides a unified `devforge` CLI entry point delegating to sub-tools: api-contract-guardian, json2sql, deploydiff, configdrift, apighost, apiauth, envault, schemaforge, click-to-mcp, and deadcode.

## Build & Test Commands
- Install: `pip install -e .[all]` or `pip install devforge-tools`
- Install all tools: `pip install devforge-tools[all]`
- Install: `pip install -e ".[all]"` or `pip install "git+https://github.com/Coding-Dev-Tools/devforge-cli.git[all]"` (NOTE: `devforge-tools` is not on public PyPI — use the `git+` form)
- Test: `pytest tests/` (or `python -m pytest tests/ -v --tb=short`)
- Lint: `ruff check .`
- Build: `pip install build twine && python -m build && twine check dist/*`
Expand Down
27 changes: 11 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

**The `devforge` command — one install, ten developer CLI tools.**

[![PyPI](https://img.shields.io/pypi/v/devforge-tools)](https://pypi.org/project/devforge-tools/)
[![Python Versions](https://img.shields.io/pypi/pyversions/devforge-tools)](https://pypi.org/project/devforge-tools/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Ten production-ready CLI tools for API contracts, SQL generation, infrastructure diffs, config drift, API mocking, key management, env syncing, schema conversion, MCP servers, and dead code removal — in a single package. Install one meta-package and get immediate access to all tools via the unified `devforge` command.
Expand All @@ -18,31 +16,28 @@ Ten production-ready CLI tools for API contracts, SQL generation, infrastructure

## Why the Suite?

Instead of installing ten separate tools and learning ten different CLIs, `pip install devforge-tools[all]` gives you:
Instead of installing ten separate tools and learning ten different CLIs, the `devforge` meta-package gives you:

- **Single CLI** (`devforge`) to invoke any tool — no context switching
- **Consistent flags, output formats, and help** across all tools
- **Shared configuration** — one install, all tools

## Installation

> **Install note:** `devforge-tools` is **not published on public PyPI**. Install it directly from the GitHub source with the `git+` form below (the only verified-working pip path right now).

```bash
# Install everything (recommended)
pip install devforge-tools[all]

# Or install individual tools
pip install devforge-tools[guard] # API Contract Guardian
pip install devforge-tools[sql] # json2sql
pip install devforge-tools[deploy] # DeployDiff
pip install devforge-tools[drift] # ConfigDrift
pip install devforge-tools[ghost] # APIGhost
pip install devforge-tools[auth] # APIAuth
pip install devforge-tools[envault] # Envault
pip install devforge-tools[schema] # SchemaForge
pip install devforge-tools[mcp] # click-to-mcp
pip install devforge-tools[deadcode] # DeadCode
pip install "git+https://github.com/Coding-Dev-Tools/devforge-cli.git[all]"

# Or clone and install locally
git clone https://github.com/Coding-Dev-Tools/devforge-cli.git
cd devforge-cli
pip install -e ".[all]"
```

Each tool can also be installed on its own from its own repo (e.g. `pip install git+https://github.com/Coding-Dev-Tools/apighost.git`). See each tool's README for details.

## Usage

```bash
Expand Down
13 changes: 9 additions & 4 deletions src/devforge/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ def list_tools(
)

console.print(table)
console.print("\n[dim]Install individually:[/dim] [green]pip install devforge-tools[guard][/green]")
console.print("[dim]Install all:[/dim] [green]pip install devforge-tools[all][/green]")
console.print(
'\n[dim]Install:[/dim] [green]pip install "git+https://github.com/Coding-Dev-Tools/devforge-cli.git[all]"[/green]'
)
console.print("[dim](devforge-tools is not on public PyPI — use the git+ form above.)[/dim]")


@app.command()
Expand All @@ -96,7 +98,9 @@ def install(
console.print(f"Available: {', '.join(TOOLS.keys())}, 'all'")
raise typer.Exit(code=1)

pkg = f"devforge-tools[{extras}]"
# devforge-tools is NOT published on public PyPI — install from GitHub source.
repo_url = "https://github.com/Coding-Dev-Tools/devforge-cli.git"
pkg = f"git+{repo_url}[{extras}]"
console.print(f"[yellow]Installing {pkg}...[/yellow]")
try:
result = subprocess.run([sys.executable, "-m", "pip", "install", pkg], capture_output=True, text=True)
Expand Down Expand Up @@ -159,7 +163,8 @@ def dispatch(ctx: typer.Context):
if not _is_tool_installed(module_name):
console.print(
f"[red]Tool '{tool_name}' is not installed.[/red]\n"
f"Run: [green]pip install devforge-tools\\[{tool_name}][/green]"
f'Run: [green]pip install "git+https://github.com/Coding-Dev-Tools/devforge-cli.git\\[{tool_name}]"[/green]',
soft_wrap=True,
)
raise typer.Exit(code=1)

Expand Down
11 changes: 6 additions & 5 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ def test_install_all_uses_all_extra(self, mock_run):
assert "Successfully" in result.stdout
mock_run.assert_called_once()
call_args = mock_run.call_args[0][0] # positional arg: the command list
# Must contain "devforge-tools[all]", not "devforge-tools[guard,sql,...]"
pkg_arg = next((a for a in call_args if a.startswith("devforge-tools[")), None)
assert pkg_arg == "devforge-tools[all]", f"Expected devforge-tools[all], got {pkg_arg}"
# Must contain the git+ URL with [all] extra, not a comma-joined list
pkg_arg = next((a for a in call_args if "devforge-cli.git[" in a), None)
expected = "git+https://github.com/Coding-Dev-Tools/devforge-cli.git[all]"
assert pkg_arg == expected, f"Expected {expected}, got {pkg_arg}"

def test_install_unknown_tool(self):
"""Error on unknown tool name."""
Expand Down Expand Up @@ -121,7 +122,7 @@ def test_dispatch_not_installed_shows_install_hint(self, _mock):
result = runner.invoke(app, ["guard"])
assert result.exit_code == 1
assert "not installed" in result.stdout
assert "pip install devforge-tools[guard]" in result.stdout
assert 'pip install "git+https://github.com/Coding-Dev-Tools/devforge-cli.git[guard]"' in result.stdout

@mock.patch("devforge.cli._is_tool_installed", return_value=True)
@mock.patch("devforge.cli.subprocess.run")
Expand Down Expand Up @@ -165,7 +166,7 @@ def test_dispatch_install_hint_escapes_extra_brackets(self, _mock):
"""
result = runner.invoke(app, ["guard"])
assert result.exit_code == 1
assert "pip install devforge-tools[guard]" in result.stdout
assert 'pip install "git+https://github.com/Coding-Dev-Tools/devforge-cli.git[guard]"' in result.stdout


class TestHelp:
Expand Down
Loading