diff --git a/AGENTS.md b/AGENTS.md index 21b34e9..c0e12fb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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/*` diff --git a/README.md b/README.md index 59abc0e..738b485 100644 --- a/README.md +++ b/README.md @@ -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. @@ -18,7 +16,7 @@ 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 @@ -26,23 +24,20 @@ Instead of installing ten separate tools and learning ten different CLIs, `pip i ## 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 diff --git a/src/devforge/cli.py b/src/devforge/cli.py index a5e048b..5abac27 100644 --- a/src/devforge/cli.py +++ b/src/devforge/cli.py @@ -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() @@ -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) @@ -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) diff --git a/tests/test_cli.py b/tests/test_cli.py index 5a934fb..022df80 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -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.""" @@ -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") @@ -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: