rocketsmith 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rocketsmith-0.0.1/LICENSE +21 -0
- rocketsmith-0.0.1/PKG-INFO +54 -0
- rocketsmith-0.0.1/README.md +37 -0
- rocketsmith-0.0.1/pyproject.toml +45 -0
- rocketsmith-0.0.1/setup.cfg +4 -0
- rocketsmith-0.0.1/src/rocketsmith/__init__.py +19 -0
- rocketsmith-0.0.1/src/rocketsmith/cli/__init__.py +16 -0
- rocketsmith-0.0.1/src/rocketsmith/cli/__main__.py +26 -0
- rocketsmith-0.0.1/src/rocketsmith/cli/options.py +15 -0
- rocketsmith-0.0.1/src/rocketsmith/cli/version.py +20 -0
- rocketsmith-0.0.1/src/rocketsmith/data/__init__.py +5 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/__init__.py +0 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/__main__.py +16 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/cli/__init__.py +10 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/cli/__main__.py +8 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/cli/development.py +46 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/cli/install.py +43 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/cli/uninstall.py +21 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/install.py +123 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/types.py +25 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/uninstall.py +91 -0
- rocketsmith-0.0.1/src/rocketsmith/mcp/utils.py +13 -0
- rocketsmith-0.0.1/src/rocketsmith/py.typed +0 -0
- rocketsmith-0.0.1/src/rocketsmith/workspace/__init__.py +0 -0
- rocketsmith-0.0.1/src/rocketsmith/workspace/cli/__init__.py +6 -0
- rocketsmith-0.0.1/src/rocketsmith/workspace/cli/__main__.py +8 -0
- rocketsmith-0.0.1/src/rocketsmith/workspace/cli/create.py +35 -0
- rocketsmith-0.0.1/src/rocketsmith/workspace/create.py +20 -0
- rocketsmith-0.0.1/src/rocketsmith/workspace/mcp.py +58 -0
- rocketsmith-0.0.1/src/rocketsmith.egg-info/PKG-INFO +54 -0
- rocketsmith-0.0.1/src/rocketsmith.egg-info/SOURCES.txt +33 -0
- rocketsmith-0.0.1/src/rocketsmith.egg-info/dependency_links.txt +1 -0
- rocketsmith-0.0.1/src/rocketsmith.egg-info/entry_points.txt +2 -0
- rocketsmith-0.0.1/src/rocketsmith.egg-info/requires.txt +5 -0
- rocketsmith-0.0.1/src/rocketsmith.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peter Pak
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rocketsmith
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Let agents design, simulate, and build your rocket.
|
|
5
|
+
Author-email: Peter Pak <ppak10@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/ppak10/RocketSmith
|
|
7
|
+
Project-URL: Issues, https://github.com/ppak10/RocketSmith/issues
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: mcp>=1.12.3
|
|
12
|
+
Requires-Dist: pydantic>=2.11.7
|
|
13
|
+
Requires-Dist: rich>=14.0.0
|
|
14
|
+
Requires-Dist: typer>=0.16.0
|
|
15
|
+
Requires-Dist: workspace-agent>=0.1.9
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
[](https://github.com/ppak10/RocketSmith/actions/workflows/pytest.yml)
|
|
19
|
+
|
|
20
|
+
# RocketSmith <img src="https://cdn.jsdelivr.net/npm/lucide-static/icons/rocket.svg" width="32" height="32" />
|
|
21
|
+
|
|
22
|
+
Let agents design, simulate, and build your rocket.
|
|
23
|
+
|
|
24
|
+
## Getting Started
|
|
25
|
+
### Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv add rocketsmith
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Agent
|
|
32
|
+
#### Claude Code
|
|
33
|
+
|
|
34
|
+
1. Install MCP tools and Agent
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
rocketsmith mcp install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Claude Desktop
|
|
41
|
+
|
|
42
|
+
1. Install MCP tools
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
rocketsmith mcp install claude-desktop --project-path /path/to/RocketSmith
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Note: After installation, restart Claude Desktop for the changes to take effect.
|
|
49
|
+
|
|
50
|
+
### CLI (`rocketsmith --help`)
|
|
51
|
+
#### Create Workspace (via `workspace-agent`)
|
|
52
|
+
```bash
|
|
53
|
+
rocketsmith workspace create <workspace-name>
|
|
54
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[](https://github.com/ppak10/RocketSmith/actions/workflows/pytest.yml)
|
|
2
|
+
|
|
3
|
+
# RocketSmith <img src="https://cdn.jsdelivr.net/npm/lucide-static/icons/rocket.svg" width="32" height="32" />
|
|
4
|
+
|
|
5
|
+
Let agents design, simulate, and build your rocket.
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
### Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
uv add rocketsmith
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### Agent
|
|
15
|
+
#### Claude Code
|
|
16
|
+
|
|
17
|
+
1. Install MCP tools and Agent
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
rocketsmith mcp install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
#### Claude Desktop
|
|
24
|
+
|
|
25
|
+
1. Install MCP tools
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
rocketsmith mcp install claude-desktop --project-path /path/to/RocketSmith
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Note: After installation, restart Claude Desktop for the changes to take effect.
|
|
32
|
+
|
|
33
|
+
### CLI (`rocketsmith --help`)
|
|
34
|
+
#### Create Workspace (via `workspace-agent`)
|
|
35
|
+
```bash
|
|
36
|
+
rocketsmith workspace create <workspace-name>
|
|
37
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rocketsmith"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name = "Peter Pak", email = "ppak10@gmail.com" },
|
|
6
|
+
]
|
|
7
|
+
description = "Let agents design, simulate, and build your rocket."
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"mcp>=1.12.3",
|
|
12
|
+
"pydantic>=2.11.7",
|
|
13
|
+
"rich>=14.0.0",
|
|
14
|
+
"typer>=0.16.0",
|
|
15
|
+
"workspace-agent>=0.1.9",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
Homepage = "https://github.com/ppak10/RocketSmith"
|
|
20
|
+
Issues = "https://github.com/ppak10/RocketSmith/issues"
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
rocketsmith = "rocketsmith.cli:app"
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["src"]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.package-data]
|
|
29
|
+
"rocketsmith.data" = ["**/*.md"]
|
|
30
|
+
|
|
31
|
+
[tool.black]
|
|
32
|
+
line-length = 88
|
|
33
|
+
target-version = ["py310"]
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"black>=25.1.0",
|
|
38
|
+
"coverage>=7.10.5",
|
|
39
|
+
"pre-commit>=4.3.0",
|
|
40
|
+
"pytest>=8.4.1",
|
|
41
|
+
"pytest-cov>=6.2.1",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
filterwarnings = []
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
__author__ = "Peter Pak"
|
|
2
|
+
__email__ = "ppak10@gmail.com"
|
|
3
|
+
|
|
4
|
+
# Set multiprocessing start method to 'spawn' for compatibility with MCP server
|
|
5
|
+
# This ensures consistent behavior across platforms (Linux uses 'fork' by default,
|
|
6
|
+
# macOS uses 'spawn') and prevents issues with forking async/MCP server state
|
|
7
|
+
import multiprocessing
|
|
8
|
+
import sys
|
|
9
|
+
import warnings
|
|
10
|
+
|
|
11
|
+
if sys.platform != "win32": # spawn is already default on Windows
|
|
12
|
+
try:
|
|
13
|
+
multiprocessing.set_start_method("spawn", force=True)
|
|
14
|
+
except RuntimeError:
|
|
15
|
+
# Method already set, ignore
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
# Suppress tqdm experimental warning for rich integration
|
|
19
|
+
warnings.filterwarnings("ignore", message=".*rich is experimental.*")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .__main__ import app
|
|
2
|
+
|
|
3
|
+
# from .version import register_version
|
|
4
|
+
|
|
5
|
+
from rocketsmith.mcp.cli import app as mcp_app
|
|
6
|
+
from rocketsmith.workspace.cli import app as workspace_app
|
|
7
|
+
|
|
8
|
+
__all__ = ["app"]
|
|
9
|
+
|
|
10
|
+
app.add_typer(mcp_app, name="mcp", rich_help_panel="Configuration Commands")
|
|
11
|
+
app.add_typer(workspace_app, name="workspace", rich_help_panel="Configuration Commands")
|
|
12
|
+
|
|
13
|
+
# _ = register_version(app)
|
|
14
|
+
|
|
15
|
+
if __name__ == "__main__":
|
|
16
|
+
app()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import typer
|
|
3
|
+
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich import print as rprint
|
|
6
|
+
|
|
7
|
+
app = typer.Typer(
|
|
8
|
+
name="rocketsmith",
|
|
9
|
+
help="RocketSmith",
|
|
10
|
+
add_completion=False,
|
|
11
|
+
no_args_is_help=True,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _rich_exception_handler(exc_type, exc_value, exc_traceback):
|
|
16
|
+
"""Handle exceptions with rich formatting."""
|
|
17
|
+
if exc_type is KeyboardInterrupt:
|
|
18
|
+
rprint("\n ⚠️ [yellow]Operation cancelled by user[/yellow]")
|
|
19
|
+
sys.exit(1)
|
|
20
|
+
else:
|
|
21
|
+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
sys.__excepthook__ = _rich_exception_handler
|
|
25
|
+
|
|
26
|
+
console = Console()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from typing_extensions import Annotated
|
|
4
|
+
|
|
5
|
+
VerboseOption = Annotated[
|
|
6
|
+
bool | None, typer.Option("--verbose", "-v", help="Enable verbose logging")
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
NumProc = Annotated[
|
|
10
|
+
int,
|
|
11
|
+
typer.Option(
|
|
12
|
+
"--num-proc",
|
|
13
|
+
help="Enable multiprocessing by specifying number of processes to use.",
|
|
14
|
+
),
|
|
15
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import importlib.metadata
|
|
2
|
+
import typer
|
|
3
|
+
|
|
4
|
+
from rich import print as rprint
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def register_version(app: typer.Typer):
|
|
8
|
+
@app.command()
|
|
9
|
+
def version() -> None:
|
|
10
|
+
"""Show the installed version of `rocketsmith` package."""
|
|
11
|
+
try:
|
|
12
|
+
version = importlib.metadata.version("rocketsmith")
|
|
13
|
+
rprint(f"✅ rocketsmith version {version}")
|
|
14
|
+
except importlib.metadata.PackageNotFoundError:
|
|
15
|
+
rprint(
|
|
16
|
+
"⚠️ [yellow]rocketsmith version unknown (package not installed)[/yellow]"
|
|
17
|
+
)
|
|
18
|
+
raise typer.Exit()
|
|
19
|
+
|
|
20
|
+
return version
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from mcp.server.fastmcp import FastMCP
|
|
2
|
+
|
|
3
|
+
from rocketsmith.workspace.mcp import register_workspace_create
|
|
4
|
+
|
|
5
|
+
app = FastMCP(name="rocketsmith")
|
|
6
|
+
|
|
7
|
+
_ = register_workspace_create(app)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
"""Entry point for the direct execution server."""
|
|
12
|
+
app.run()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if __name__ == "__main__":
|
|
16
|
+
main()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .__main__ import app
|
|
2
|
+
from .development import register_mcp_development
|
|
3
|
+
from .install import register_mcp_install
|
|
4
|
+
from .uninstall import register_mcp_uninstall
|
|
5
|
+
|
|
6
|
+
_ = register_mcp_development(app)
|
|
7
|
+
_ = register_mcp_install(app)
|
|
8
|
+
_ = register_mcp_uninstall(app)
|
|
9
|
+
|
|
10
|
+
__all__ = ["app"]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from importlib.resources import files
|
|
7
|
+
from rich import print as rprint
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def register_mcp_development(app: typer.Typer):
|
|
11
|
+
@app.command(name="development")
|
|
12
|
+
def mcp_development() -> None:
|
|
13
|
+
from mcp.cli import cli
|
|
14
|
+
|
|
15
|
+
rprint(f"Starting MCP Development Server")
|
|
16
|
+
|
|
17
|
+
# Get the correct npx command
|
|
18
|
+
npx_cmd = cli._get_npx_command()
|
|
19
|
+
|
|
20
|
+
if not npx_cmd:
|
|
21
|
+
cli.logger.error(
|
|
22
|
+
"npx not found. Please ensure Node.js and npm are properly installed and added to your system PATH."
|
|
23
|
+
)
|
|
24
|
+
raise typer.Exit(1)
|
|
25
|
+
|
|
26
|
+
# Run the MCP Inspector command with shell=True on Windows
|
|
27
|
+
shell = sys.platform == "win32"
|
|
28
|
+
|
|
29
|
+
file_spec = files("rocketsmith.mcp").joinpath("__main__.py")
|
|
30
|
+
|
|
31
|
+
print(file_spec)
|
|
32
|
+
|
|
33
|
+
uv_cmd = ["uv", "run", "--with", "mcp", "mcp", "run", str(file_spec)]
|
|
34
|
+
print(f"uv_cmd: {uv_cmd}")
|
|
35
|
+
|
|
36
|
+
process = subprocess.run(
|
|
37
|
+
[npx_cmd, "@modelcontextprotocol/inspector"] + uv_cmd,
|
|
38
|
+
check=True,
|
|
39
|
+
shell=shell,
|
|
40
|
+
env=dict(os.environ.items()),
|
|
41
|
+
)
|
|
42
|
+
_ = typer.Exit(process.returncode)
|
|
43
|
+
rprint(f"✅ MCP Development Running")
|
|
44
|
+
|
|
45
|
+
_ = app.command(name="dev")(mcp_development)
|
|
46
|
+
return mcp_development
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from typing_extensions import Annotated
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from rich import print as rprint
|
|
6
|
+
|
|
7
|
+
from rocketsmith.mcp.install import install
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def register_mcp_install(app: typer.Typer):
|
|
11
|
+
@app.command(name="install")
|
|
12
|
+
def mcp_install(
|
|
13
|
+
client: Annotated[
|
|
14
|
+
str,
|
|
15
|
+
typer.Argument(
|
|
16
|
+
help="Target client to install for. Options: claude-code, claude-desktop, gemini-cli, codex"
|
|
17
|
+
),
|
|
18
|
+
] = "claude-code",
|
|
19
|
+
include_agent: Annotated[bool, typer.Option("--include-agent")] = False,
|
|
20
|
+
project_path: Annotated[str | None, typer.Option("--project-path")] = None,
|
|
21
|
+
dev: Annotated[bool, typer.Option("--dev")] = False,
|
|
22
|
+
) -> None:
|
|
23
|
+
import rocketsmith
|
|
24
|
+
|
|
25
|
+
# Determine project root path
|
|
26
|
+
if dev:
|
|
27
|
+
rocketsmith_path = Path(rocketsmith.__file__).parents[2]
|
|
28
|
+
elif project_path:
|
|
29
|
+
rocketsmith_path = Path(project_path)
|
|
30
|
+
else:
|
|
31
|
+
# Path(rocketsmith.__file__) example:
|
|
32
|
+
# /GitHub/rocketsmith-agent/.venv/lib/python3.13/site-packages/rocketsmith
|
|
33
|
+
# Going up 5 levels to get to the project root
|
|
34
|
+
rocketsmith_path = Path(rocketsmith.__file__).parents[5]
|
|
35
|
+
|
|
36
|
+
rprint(
|
|
37
|
+
f"[bold green]Using `rocketsmith` packaged under project path:[/bold green] {rocketsmith_path}"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
install(rocketsmith_path, client=client, include_agent=include_agent)
|
|
41
|
+
|
|
42
|
+
_ = app.command(name="install")(mcp_install)
|
|
43
|
+
return mcp_install
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from typing_extensions import Annotated
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def register_mcp_uninstall(app: typer.Typer):
|
|
7
|
+
@app.command(name="uninstall")
|
|
8
|
+
def mcp_uninstall(
|
|
9
|
+
client: Annotated[
|
|
10
|
+
str,
|
|
11
|
+
typer.Argument(
|
|
12
|
+
help="Target client to uninstall. Options: claude-code, claude-desktop, gemini-cli, codex"
|
|
13
|
+
),
|
|
14
|
+
] = "claude-code",
|
|
15
|
+
) -> None:
|
|
16
|
+
from rocketsmith.mcp.uninstall import uninstall
|
|
17
|
+
|
|
18
|
+
uninstall(client=client)
|
|
19
|
+
|
|
20
|
+
_ = app.command(name="uninstall")(mcp_uninstall)
|
|
21
|
+
return mcp_uninstall
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from rich import print as rprint
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def install(path: Path, client: str, include_agent: bool = True) -> None:
|
|
10
|
+
match client:
|
|
11
|
+
case "claude-code":
|
|
12
|
+
cmd = [
|
|
13
|
+
"claude",
|
|
14
|
+
"mcp",
|
|
15
|
+
"add-json",
|
|
16
|
+
"rocketsmith",
|
|
17
|
+
f'{{"command": "uv", "args": ["--directory", "{path}", "run", "-m", "rocketsmith.mcp"]}}',
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
case "claude-desktop":
|
|
21
|
+
# Determine config file path based on platform
|
|
22
|
+
if sys.platform == "darwin":
|
|
23
|
+
config_path = (
|
|
24
|
+
Path.home()
|
|
25
|
+
/ "Library"
|
|
26
|
+
/ "Application Support"
|
|
27
|
+
/ "Claude"
|
|
28
|
+
/ "claude_desktop_config.json"
|
|
29
|
+
)
|
|
30
|
+
elif sys.platform == "win32":
|
|
31
|
+
config_path = (
|
|
32
|
+
Path.home()
|
|
33
|
+
/ "AppData"
|
|
34
|
+
/ "Roaming"
|
|
35
|
+
/ "Claude"
|
|
36
|
+
/ "claude_desktop_config.json"
|
|
37
|
+
)
|
|
38
|
+
else: # Linux
|
|
39
|
+
config_path = (
|
|
40
|
+
Path.home() / ".config" / "Claude" / "claude_desktop_config.json"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Ensure config directory exists
|
|
44
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
|
|
46
|
+
# Read existing config or create new one
|
|
47
|
+
if config_path.exists():
|
|
48
|
+
with open(config_path, "r") as f:
|
|
49
|
+
config = json.load(f)
|
|
50
|
+
rprint(f"[blue]Found existing config at:[/blue] {config_path}")
|
|
51
|
+
else:
|
|
52
|
+
config = {}
|
|
53
|
+
rprint(f"[yellow]Creating new config at:[/yellow] {config_path}")
|
|
54
|
+
|
|
55
|
+
# Ensure mcpServers section exists
|
|
56
|
+
if "mcpServers" not in config:
|
|
57
|
+
config["mcpServers"] = {}
|
|
58
|
+
|
|
59
|
+
# Add rocketsmith server
|
|
60
|
+
rprint("[blue]Adding 'rocketsmith' MCP server to config...[/blue]")
|
|
61
|
+
config["mcpServers"]["rocketsmith"] = {
|
|
62
|
+
"command": "uv",
|
|
63
|
+
"args": ["--directory", str(path), "run", "-m", "rocketsmith.mcp"],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Write config back
|
|
67
|
+
with open(config_path, "w") as f:
|
|
68
|
+
json.dump(config, f, indent=2)
|
|
69
|
+
|
|
70
|
+
rprint(
|
|
71
|
+
f"[bold green]Successfully updated config at:[/bold green] {config_path}"
|
|
72
|
+
)
|
|
73
|
+
rprint(
|
|
74
|
+
"[yellow]Note: Please restart Claude Desktop for changes to take effect.[/yellow]"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Skip agent installation as Claude Desktop doesn't support custom agents
|
|
78
|
+
if include_agent:
|
|
79
|
+
rprint(
|
|
80
|
+
"[yellow]Note: Claude Desktop does not support custom agents like Claude Code does.[/yellow]"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return # Early return since we don't need to run subprocess command
|
|
84
|
+
|
|
85
|
+
case "gemini-cli":
|
|
86
|
+
cmd = [
|
|
87
|
+
"gemini",
|
|
88
|
+
"mcp",
|
|
89
|
+
"add",
|
|
90
|
+
"rocketsmith",
|
|
91
|
+
"uv",
|
|
92
|
+
"--directory",
|
|
93
|
+
f"{path}",
|
|
94
|
+
"run",
|
|
95
|
+
"-m",
|
|
96
|
+
"rocketsmith.mcp",
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
case "codex":
|
|
100
|
+
cmd = [
|
|
101
|
+
"codex",
|
|
102
|
+
"mcp",
|
|
103
|
+
"add",
|
|
104
|
+
"rocketsmith",
|
|
105
|
+
"uv",
|
|
106
|
+
"--directory",
|
|
107
|
+
f"{path}",
|
|
108
|
+
"run",
|
|
109
|
+
"-m",
|
|
110
|
+
"rocketsmith.mcp",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
case _:
|
|
114
|
+
rprint("[yellow]No client provided.[/yellow]")
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
rprint(f"[blue]Running command:[/blue] {' '.join(cmd)}")
|
|
118
|
+
subprocess.run(cmd, check=True)
|
|
119
|
+
except subprocess.CalledProcessError as e:
|
|
120
|
+
rprint(f"[red]Command failed with return code {e.returncode}[/red]")
|
|
121
|
+
rprint(f"[red]Error output: {e.stderr}[/red]" if e.stderr else "")
|
|
122
|
+
except Exception as e:
|
|
123
|
+
rprint(f"[red]Unexpected error running command:[/red] {e}")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from typing import Union, Dict, Any, TypeVar, Generic
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
|
|
4
|
+
# Generic type for the success data
|
|
5
|
+
T = TypeVar("T")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ToolError(BaseModel):
|
|
9
|
+
"""Standard error response for MCP tools."""
|
|
10
|
+
|
|
11
|
+
success: bool = False
|
|
12
|
+
error: str
|
|
13
|
+
error_code: str
|
|
14
|
+
details: Dict[str, Any] = {}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ToolSuccess(BaseModel, Generic[T]):
|
|
18
|
+
"""Standard success response for MCP tools."""
|
|
19
|
+
|
|
20
|
+
success: bool = True
|
|
21
|
+
data: T
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Type alias for tool responses
|
|
25
|
+
ToolResponse = Union[ToolSuccess[T], ToolError]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from rich import print as rprint
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def uninstall(client: str) -> None:
|
|
10
|
+
cmd = None
|
|
11
|
+
match client:
|
|
12
|
+
case "claude-code":
|
|
13
|
+
cmd = ["claude", "mcp", "remove", "rocketsmith"]
|
|
14
|
+
|
|
15
|
+
case "claude-desktop":
|
|
16
|
+
# Determine config file path based on platform
|
|
17
|
+
if sys.platform == "darwin":
|
|
18
|
+
config_path = (
|
|
19
|
+
Path.home()
|
|
20
|
+
/ "Library"
|
|
21
|
+
/ "Application Support"
|
|
22
|
+
/ "Claude"
|
|
23
|
+
/ "claude_desktop_config.json"
|
|
24
|
+
)
|
|
25
|
+
elif sys.platform == "win32":
|
|
26
|
+
config_path = (
|
|
27
|
+
Path.home()
|
|
28
|
+
/ "AppData"
|
|
29
|
+
/ "Roaming"
|
|
30
|
+
/ "Claude"
|
|
31
|
+
/ "claude_desktop_config.json"
|
|
32
|
+
)
|
|
33
|
+
else: # Linux
|
|
34
|
+
config_path = (
|
|
35
|
+
Path.home() / ".config" / "Claude" / "claude_desktop_config.json"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Check if config file exists
|
|
39
|
+
if not config_path.exists():
|
|
40
|
+
rprint(f"[yellow]Config file not found at:[/yellow] {config_path}")
|
|
41
|
+
rprint("[yellow]Nothing to uninstall.[/yellow]")
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
# Read existing config
|
|
45
|
+
try:
|
|
46
|
+
with open(config_path, "r") as f:
|
|
47
|
+
config = json.load(f)
|
|
48
|
+
except json.JSONDecodeError:
|
|
49
|
+
rprint(f"[red]Error reading config file at:[/red] {config_path}")
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
# Remove rocketsmith server
|
|
53
|
+
if "mcpServers" in config and "rocketsmith" in config["mcpServers"]:
|
|
54
|
+
del config["mcpServers"]["rocketsmith"]
|
|
55
|
+
rprint("[blue]Removed 'rocketsmith' MCP server from config[/blue]")
|
|
56
|
+
else:
|
|
57
|
+
rprint(
|
|
58
|
+
"[yellow]'rocketsmith' MCP server not found in config[/yellow]"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Write config back
|
|
62
|
+
with open(config_path, "w") as f:
|
|
63
|
+
json.dump(config, f, indent=2)
|
|
64
|
+
|
|
65
|
+
rprint(
|
|
66
|
+
f"[bold green]Successfully updated config at:[/bold green] {config_path}"
|
|
67
|
+
)
|
|
68
|
+
rprint(
|
|
69
|
+
"[yellow]Note: Please restart Claude Desktop for changes to take effect.[/yellow]"
|
|
70
|
+
)
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
case "gemini-cli":
|
|
74
|
+
cmd = ["gemini", "mcp", "remove", "rocketsmith"]
|
|
75
|
+
|
|
76
|
+
case "codex":
|
|
77
|
+
cmd = ["codex", "mcp", "remove", "rocketsmith"]
|
|
78
|
+
|
|
79
|
+
case _:
|
|
80
|
+
rprint("[yellow]No client provided.[/yellow]\n")
|
|
81
|
+
|
|
82
|
+
if cmd is not None:
|
|
83
|
+
try:
|
|
84
|
+
rprint(f"[blue]Running command:[/blue] {' '.join(cmd)}")
|
|
85
|
+
subprocess.run(cmd, check=True)
|
|
86
|
+
|
|
87
|
+
except subprocess.CalledProcessError as e:
|
|
88
|
+
rprint(f"[red]Command failed with return code {e.returncode}[/red]")
|
|
89
|
+
rprint(f"[red]Error output: {e.stderr}[/red]" if e.stderr else "")
|
|
90
|
+
except Exception as e:
|
|
91
|
+
rprint(f"[red]Unexpected error running command:[/red] {e}")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from rocketsmith.mcp.types import T, ToolError, ToolSuccess
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# Convenience function to create error responses
|
|
5
|
+
def tool_error(message: str, code: str, **details) -> ToolError:
|
|
6
|
+
"""Create a standardized tool error response."""
|
|
7
|
+
return ToolError(error=message, error_code=code, details=details)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Convenience function to create success responses
|
|
11
|
+
def tool_success(data: T) -> ToolSuccess[T]:
|
|
12
|
+
"""Create a standardized tool success response."""
|
|
13
|
+
return ToolSuccess(data=data)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from rich import print as rprint
|
|
5
|
+
from typing_extensions import Annotated
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register_workspace_create(app: typer.Typer):
|
|
9
|
+
@app.command(name="create")
|
|
10
|
+
def workspace_create(
|
|
11
|
+
workspace_name: str,
|
|
12
|
+
workspaces_path: Path | None = None,
|
|
13
|
+
force: Annotated[
|
|
14
|
+
bool, typer.Option("--force", help="Overwrite existing subfolder")
|
|
15
|
+
] = False,
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Create a folder to store data related to a workspace."""
|
|
18
|
+
from rocketsmith.workspace.create import create_rocketsmith_workspace
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
workspace = create_rocketsmith_workspace(
|
|
22
|
+
workspace_name=workspace_name,
|
|
23
|
+
workspaces_path=workspaces_path,
|
|
24
|
+
force=force,
|
|
25
|
+
)
|
|
26
|
+
rprint(f"✅ Workspace created at: {workspace.path}")
|
|
27
|
+
except FileExistsError:
|
|
28
|
+
rprint(f"⚠️ [yellow]Workspace: `{workspace_name}` already exists.[/yellow]")
|
|
29
|
+
rprint("Use [cyan]--force[/cyan] to overwrite, or edit the existing file.")
|
|
30
|
+
_ = typer.Exit()
|
|
31
|
+
except:
|
|
32
|
+
rprint("⚠️ [yellow]Unable to create workspace directory[/yellow]")
|
|
33
|
+
_ = typer.Exit()
|
|
34
|
+
|
|
35
|
+
return workspace_create
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from wa import create_workspace, Workspace
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def create_rocketsmith_workspace(
|
|
7
|
+
workspace_name: str,
|
|
8
|
+
workspaces_path: Path | None = None,
|
|
9
|
+
force: bool = False,
|
|
10
|
+
**kwargs,
|
|
11
|
+
) -> Workspace:
|
|
12
|
+
"""
|
|
13
|
+
Create RocketSmith Workspace class object and folder.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
workspace = create_workspace(
|
|
17
|
+
workspace_name=workspace_name, workspaces_path=workspaces_path, force=force
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
return workspace
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from mcp.server.fastmcp import FastMCP
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def register_workspace_create(app: FastMCP):
|
|
8
|
+
from rocketsmith.mcp.types import ToolSuccess, ToolError
|
|
9
|
+
from rocketsmith.mcp.utils import tool_success, tool_error
|
|
10
|
+
from wa import Workspace
|
|
11
|
+
|
|
12
|
+
@app.tool(
|
|
13
|
+
title="Create RocketSmith Workspace",
|
|
14
|
+
description="Creates workspace folder for use with rocketsmith tools.",
|
|
15
|
+
structured_output=True,
|
|
16
|
+
)
|
|
17
|
+
async def workspace_create(
|
|
18
|
+
workspace_name: str,
|
|
19
|
+
workspaces_path: Path | None = None,
|
|
20
|
+
force: bool = False,
|
|
21
|
+
) -> Union[ToolSuccess[Workspace], ToolError]:
|
|
22
|
+
"""
|
|
23
|
+
Initialize rocketsmith workspace folder.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
workspace_name: Name of folder to initialize.
|
|
27
|
+
workspaces_path: Path of folder containing workspaces.
|
|
28
|
+
force: Overwrite existing workspace.
|
|
29
|
+
"""
|
|
30
|
+
from rocketsmith.workspace.create import create_rocketsmith_workspace
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
workspace = create_rocketsmith_workspace(
|
|
34
|
+
workspace_name=workspace_name,
|
|
35
|
+
workspaces_path=workspaces_path,
|
|
36
|
+
force=force,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
return tool_success(workspace)
|
|
40
|
+
|
|
41
|
+
except PermissionError as e:
|
|
42
|
+
return tool_error(
|
|
43
|
+
"Permission denied when creating workspace folder",
|
|
44
|
+
"PERMISSION_DENIED",
|
|
45
|
+
workspace_name=workspace_name,
|
|
46
|
+
exception_type=type(e).__name__,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
except Exception as e:
|
|
50
|
+
return tool_error(
|
|
51
|
+
"Failed to create workspace folder",
|
|
52
|
+
"WORKSPACE_CREATE_FAILED",
|
|
53
|
+
workspace_name=workspace_name,
|
|
54
|
+
exception_type=type(e).__name__,
|
|
55
|
+
exception_message=str(e),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
_ = workspace_create
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rocketsmith
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Let agents design, simulate, and build your rocket.
|
|
5
|
+
Author-email: Peter Pak <ppak10@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/ppak10/RocketSmith
|
|
7
|
+
Project-URL: Issues, https://github.com/ppak10/RocketSmith/issues
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: mcp>=1.12.3
|
|
12
|
+
Requires-Dist: pydantic>=2.11.7
|
|
13
|
+
Requires-Dist: rich>=14.0.0
|
|
14
|
+
Requires-Dist: typer>=0.16.0
|
|
15
|
+
Requires-Dist: workspace-agent>=0.1.9
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
[](https://github.com/ppak10/RocketSmith/actions/workflows/pytest.yml)
|
|
19
|
+
|
|
20
|
+
# RocketSmith <img src="https://cdn.jsdelivr.net/npm/lucide-static/icons/rocket.svg" width="32" height="32" />
|
|
21
|
+
|
|
22
|
+
Let agents design, simulate, and build your rocket.
|
|
23
|
+
|
|
24
|
+
## Getting Started
|
|
25
|
+
### Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv add rocketsmith
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Agent
|
|
32
|
+
#### Claude Code
|
|
33
|
+
|
|
34
|
+
1. Install MCP tools and Agent
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
rocketsmith mcp install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Claude Desktop
|
|
41
|
+
|
|
42
|
+
1. Install MCP tools
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
rocketsmith mcp install claude-desktop --project-path /path/to/RocketSmith
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Note: After installation, restart Claude Desktop for the changes to take effect.
|
|
49
|
+
|
|
50
|
+
### CLI (`rocketsmith --help`)
|
|
51
|
+
#### Create Workspace (via `workspace-agent`)
|
|
52
|
+
```bash
|
|
53
|
+
rocketsmith workspace create <workspace-name>
|
|
54
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/rocketsmith/__init__.py
|
|
5
|
+
src/rocketsmith/py.typed
|
|
6
|
+
src/rocketsmith.egg-info/PKG-INFO
|
|
7
|
+
src/rocketsmith.egg-info/SOURCES.txt
|
|
8
|
+
src/rocketsmith.egg-info/dependency_links.txt
|
|
9
|
+
src/rocketsmith.egg-info/entry_points.txt
|
|
10
|
+
src/rocketsmith.egg-info/requires.txt
|
|
11
|
+
src/rocketsmith.egg-info/top_level.txt
|
|
12
|
+
src/rocketsmith/cli/__init__.py
|
|
13
|
+
src/rocketsmith/cli/__main__.py
|
|
14
|
+
src/rocketsmith/cli/options.py
|
|
15
|
+
src/rocketsmith/cli/version.py
|
|
16
|
+
src/rocketsmith/data/__init__.py
|
|
17
|
+
src/rocketsmith/mcp/__init__.py
|
|
18
|
+
src/rocketsmith/mcp/__main__.py
|
|
19
|
+
src/rocketsmith/mcp/install.py
|
|
20
|
+
src/rocketsmith/mcp/types.py
|
|
21
|
+
src/rocketsmith/mcp/uninstall.py
|
|
22
|
+
src/rocketsmith/mcp/utils.py
|
|
23
|
+
src/rocketsmith/mcp/cli/__init__.py
|
|
24
|
+
src/rocketsmith/mcp/cli/__main__.py
|
|
25
|
+
src/rocketsmith/mcp/cli/development.py
|
|
26
|
+
src/rocketsmith/mcp/cli/install.py
|
|
27
|
+
src/rocketsmith/mcp/cli/uninstall.py
|
|
28
|
+
src/rocketsmith/workspace/__init__.py
|
|
29
|
+
src/rocketsmith/workspace/create.py
|
|
30
|
+
src/rocketsmith/workspace/mcp.py
|
|
31
|
+
src/rocketsmith/workspace/cli/__init__.py
|
|
32
|
+
src/rocketsmith/workspace/cli/__main__.py
|
|
33
|
+
src/rocketsmith/workspace/cli/create.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rocketsmith
|