spawnio 1.0.5__py3-none-any.whl
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.
- spawn/__init__.py +6 -0
- spawn/cli/__init__.py +0 -0
- spawn/cli/app.py +218 -0
- spawn/cli/noninteractive.py +204 -0
- spawn/cli/prompts.py +267 -0
- spawn/core/__init__.py +0 -0
- spawn/core/exceptions.py +7 -0
- spawn/core/models.py +21 -0
- spawn/core/registry.py +152 -0
- spawn/generators/__init__.py +0 -0
- spawn/generators/custom_structure.py +508 -0
- spawn/generators/project_generator.py +115 -0
- spawn/github/__init__.py +0 -0
- spawn/github/exceptions.py +5 -0
- spawn/github/publisher.py +69 -0
- spawn/github/validators.py +23 -0
- spawn/templates/__init__.py +0 -0
- spawn/templates/agent/__init__.py +182 -0
- spawn/templates/agent/content.py +374 -0
- spawn/templates/automation/__init__.py +100 -0
- spawn/templates/automation/content.py +181 -0
- spawn/templates/backend_api/__init__.py +243 -0
- spawn/templates/backend_api/content.py +509 -0
- spawn/templates/base.py +58 -0
- spawn/templates/chatbot/__init__.py +243 -0
- spawn/templates/chatbot/content.py +668 -0
- spawn/templates/cli_application/__init__.py +211 -0
- spawn/templates/cli_application/content.py +512 -0
- spawn/templates/data_project/__init__.py +125 -0
- spawn/templates/data_project/analysis/__init__.py +74 -0
- spawn/templates/data_project/analysis/content.py +190 -0
- spawn/templates/data_project/dashboard/__init__.py +61 -0
- spawn/templates/data_project/dashboard/content.py +135 -0
- spawn/templates/data_project/etl/__init__.py +66 -0
- spawn/templates/data_project/etl/content.py +239 -0
- spawn/templates/data_project/ml/__init__.py +62 -0
- spawn/templates/data_project/ml/content.py +239 -0
- spawn/templates/mcp_server/__init__.py +83 -0
- spawn/templates/mcp_server/content.py +161 -0
- spawn/templates/rag/__init__.py +124 -0
- spawn/templates/rag/content.py +463 -0
- spawn/templates/shared_content.py +89 -0
- spawn/utils/__init__.py +0 -0
- spawn/utils/banner.py +41 -0
- spawn/utils/console.py +3 -0
- spawn/utils/doctor.py +594 -0
- spawn/utils/git.py +132 -0
- spawn/utils/success.py +47 -0
- spawn/utils/theme.py +25 -0
- spawn/utils/uv.py +61 -0
- spawn/utils/validators.py +15 -0
- spawnio-1.0.5.dist-info/METADATA +798 -0
- spawnio-1.0.5.dist-info/RECORD +56 -0
- spawnio-1.0.5.dist-info/WHEEL +4 -0
- spawnio-1.0.5.dist-info/entry_points.txt +2 -0
- spawnio-1.0.5.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
INIT_CONTENT = ""
|
|
2
|
+
|
|
3
|
+
SERVER_CONTENT = """\
|
|
4
|
+
\"\"\"MCP server entrypoint for {project_name}.\"\"\"
|
|
5
|
+
|
|
6
|
+
from mcp.server import MCPServer
|
|
7
|
+
|
|
8
|
+
mcp = MCPServer("{project_name}")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _add(a: int, b: int) -> int:
|
|
12
|
+
return a + b
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@mcp.tool()
|
|
16
|
+
def add(a: int, b: int) -> int:
|
|
17
|
+
\"\"\"Add two numbers together.\"\"\"
|
|
18
|
+
return _add(a, b)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_server_info() -> str:
|
|
22
|
+
return "{project_name} MCP server, built with Spawn."
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@mcp.resource("info://server")
|
|
26
|
+
def server_info() -> str:
|
|
27
|
+
\"\"\"Return basic information about this MCP server.\"\"\"
|
|
28
|
+
return _get_server_info()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def main() -> None:
|
|
32
|
+
mcp.run()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
main()
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
TEST_CONTENT = """\
|
|
40
|
+
from src.server import _add, _get_server_info
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_add():
|
|
44
|
+
assert _add(2, 3) == 5
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_add_negative_numbers():
|
|
48
|
+
assert _add(-1, -1) == -2
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_server_info_returns_nonempty_string():
|
|
52
|
+
info = _get_server_info()
|
|
53
|
+
assert isinstance(info, str)
|
|
54
|
+
assert len(info) > 0
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
ENV_CONTENT = """\
|
|
58
|
+
# Environment variables for {project_name}
|
|
59
|
+
# This MCP server has no required environment variables by default.
|
|
60
|
+
# Add any secrets or configuration your tools/resources need here.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
GITHUB_ACTIONS_CI_BASE = """\
|
|
64
|
+
name: CI
|
|
65
|
+
|
|
66
|
+
on:
|
|
67
|
+
push:
|
|
68
|
+
branches: [main]
|
|
69
|
+
pull_request:
|
|
70
|
+
branches: [main]
|
|
71
|
+
|
|
72
|
+
jobs:
|
|
73
|
+
ci:
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
|
|
79
|
+
- uses: astral-sh/setup-uv@v5
|
|
80
|
+
|
|
81
|
+
- name: Install dependencies
|
|
82
|
+
run: uv sync
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
GITHUB_ACTIONS_CI_RUFF_STEP = """\
|
|
86
|
+
- name: Lint
|
|
87
|
+
run: uv run ruff check .
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
GITHUB_ACTIONS_CI_PYTEST_STEP = """\
|
|
91
|
+
- name: Test
|
|
92
|
+
run: uv run pytest
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def make_readme() -> str:
|
|
97
|
+
return """\
|
|
98
|
+
# {project_name}
|
|
99
|
+
|
|
100
|
+
An MCP (Model Context Protocol) server, generated with Spawn.
|
|
101
|
+
|
|
102
|
+
This server exposes one example tool (`add`) and one example resource
|
|
103
|
+
(`info://server`) over the `stdio` transport, ready to connect to any
|
|
104
|
+
MCP client — Claude Desktop, Claude Code, or your own client built on
|
|
105
|
+
the MCP SDK.
|
|
106
|
+
|
|
107
|
+
## Run it directly
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
uv run python -m src.server
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
It will wait on stdio for an MCP client to connect — this is normal,
|
|
114
|
+
it's not meant to be run standalone in a terminal for long.
|
|
115
|
+
|
|
116
|
+
## Connect it to Claude Desktop
|
|
117
|
+
|
|
118
|
+
Add this to your `claude_desktop_config.json`:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{{
|
|
122
|
+
"mcpServers": {{
|
|
123
|
+
"{project_name}": {{
|
|
124
|
+
"command": "uv",
|
|
125
|
+
"args": ["--directory", "/absolute/path/to/{project_name}", "run", "python", "-m", "src.server"]
|
|
126
|
+
}}
|
|
127
|
+
}}
|
|
128
|
+
}}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Replace `/absolute/path/to/{project_name}` with this project's actual
|
|
132
|
+
path, then restart Claude Desktop.
|
|
133
|
+
|
|
134
|
+
## Add your own tools and resources
|
|
135
|
+
|
|
136
|
+
Open `src/server.py`. Add a new function decorated with `@mcp.tool()`
|
|
137
|
+
for anything you want an MCP client to be able to call, or
|
|
138
|
+
`@mcp.resource("your://uri")` for anything you want it to be able to
|
|
139
|
+
read.
|
|
140
|
+
|
|
141
|
+
## Tests
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
uv run pytest
|
|
145
|
+
```
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def make_agents_md() -> str:
|
|
150
|
+
return """\
|
|
151
|
+
# {project_name}
|
|
152
|
+
|
|
153
|
+
An MCP (Model Context Protocol) server built using the `mcp` SDK's `MCPServer` class.
|
|
154
|
+
|
|
155
|
+
## Adding Tools and Resources
|
|
156
|
+
|
|
157
|
+
Open `src/server.py`.
|
|
158
|
+
|
|
159
|
+
- Add a new tool: Decorate a function with `@mcp.tool()` to expose callable tools to MCP clients.
|
|
160
|
+
- Add a new resource: Decorate a function with `@mcp.resource("uri")` to expose readable resources to MCP clients.
|
|
161
|
+
"""
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from spawn.templates.base import BaseTemplate
|
|
4
|
+
from spawn.templates.rag.content import (
|
|
5
|
+
INIT_CONTENT,
|
|
6
|
+
SAMPLE_KNOWLEDGE_CONTENT,
|
|
7
|
+
SETTINGS_CONTENT,
|
|
8
|
+
KNOWLEDGE_INDEX_CONTENT,
|
|
9
|
+
INGESTION_CONTENT,
|
|
10
|
+
RETRIEVAL_CONTENT,
|
|
11
|
+
MAIN_CONTENT,
|
|
12
|
+
TEST_CONTENT,
|
|
13
|
+
CONFTEST_CONTENT,
|
|
14
|
+
ENV_CONTENT,
|
|
15
|
+
GITHUB_ACTIONS_CI_BASE,
|
|
16
|
+
GITHUB_ACTIONS_CI_RUFF_STEP,
|
|
17
|
+
GITHUB_ACTIONS_CI_PYTEST_STEP,
|
|
18
|
+
make_readme,
|
|
19
|
+
make_agents_md,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
RAG_FOLDERS = [
|
|
23
|
+
"data",
|
|
24
|
+
"chroma_db",
|
|
25
|
+
"src/ingestion",
|
|
26
|
+
"src/retrieval",
|
|
27
|
+
"src/knowledge",
|
|
28
|
+
"src/config",
|
|
29
|
+
"tests",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _build_files() -> list:
|
|
34
|
+
return [
|
|
35
|
+
("data/sample_knowledge.md", SAMPLE_KNOWLEDGE_CONTENT),
|
|
36
|
+
("src/__init__.py", INIT_CONTENT),
|
|
37
|
+
("src/config/__init__.py", INIT_CONTENT),
|
|
38
|
+
("src/config/settings.py", SETTINGS_CONTENT),
|
|
39
|
+
("src/knowledge/__init__.py", INIT_CONTENT),
|
|
40
|
+
("src/knowledge/index.py", KNOWLEDGE_INDEX_CONTENT),
|
|
41
|
+
("src/ingestion/__init__.py", INIT_CONTENT),
|
|
42
|
+
("src/ingestion/ingest.py", INGESTION_CONTENT),
|
|
43
|
+
("src/retrieval/__init__.py", INIT_CONTENT),
|
|
44
|
+
("src/retrieval/retrieve.py", RETRIEVAL_CONTENT),
|
|
45
|
+
("src/main.py", MAIN_CONTENT),
|
|
46
|
+
("tests/__init__.py", INIT_CONTENT),
|
|
47
|
+
("tests/conftest.py", CONFTEST_CONTENT),
|
|
48
|
+
("tests/test_rag.py", TEST_CONTENT),
|
|
49
|
+
(".env.example", ENV_CONTENT),
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class RAGTemplate(BaseTemplate):
|
|
54
|
+
def __init__(self, extras: list[str] | None = None) -> None:
|
|
55
|
+
self.extras = extras or []
|
|
56
|
+
|
|
57
|
+
super().__init__(
|
|
58
|
+
name="RAG System",
|
|
59
|
+
folders=list(RAG_FOLDERS),
|
|
60
|
+
starter_files=_build_files(),
|
|
61
|
+
next_steps=[
|
|
62
|
+
"cd {project_name}",
|
|
63
|
+
"Rename .env.example to .env and add your OPENAI_API_KEY",
|
|
64
|
+
"uv run python -m src.main",
|
|
65
|
+
],
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def get_readme_content(self, context: dict) -> str | None:
|
|
69
|
+
return make_readme().format_map(context)
|
|
70
|
+
|
|
71
|
+
def get_agents_md_content(self, context: dict) -> str | None:
|
|
72
|
+
return make_agents_md().format_map(context)
|
|
73
|
+
|
|
74
|
+
def get_dependencies(self) -> list[str]:
|
|
75
|
+
base = [
|
|
76
|
+
"llama-index-core",
|
|
77
|
+
"llama-index-vector-stores-chroma",
|
|
78
|
+
"llama-index-embeddings-openai",
|
|
79
|
+
"llama-index-llms-openai",
|
|
80
|
+
"chromadb",
|
|
81
|
+
"python-dotenv",
|
|
82
|
+
]
|
|
83
|
+
if "pytest" in self.extras:
|
|
84
|
+
base.append("pytest")
|
|
85
|
+
if "ruff" in self.extras:
|
|
86
|
+
base.append("ruff")
|
|
87
|
+
return base
|
|
88
|
+
|
|
89
|
+
def post_install(self, project_path: Path) -> None:
|
|
90
|
+
pyproject = project_path / "pyproject.toml"
|
|
91
|
+
current = pyproject.read_text(encoding="utf-8")
|
|
92
|
+
additions = ""
|
|
93
|
+
|
|
94
|
+
if "pytest" in self.extras:
|
|
95
|
+
additions += "\n[tool.pytest.ini_options]\ntestpaths = [\"tests\"]\n"
|
|
96
|
+
|
|
97
|
+
if "ruff" in self.extras:
|
|
98
|
+
additions += "\n[tool.ruff]\nline-length = 88\n"
|
|
99
|
+
|
|
100
|
+
if additions:
|
|
101
|
+
pyproject.write_text(current + additions, encoding="utf-8")
|
|
102
|
+
|
|
103
|
+
if "github-actions" in self.extras:
|
|
104
|
+
workflows_path = project_path / ".github" / "workflows"
|
|
105
|
+
workflows_path.mkdir(parents=True, exist_ok=True)
|
|
106
|
+
ci = GITHUB_ACTIONS_CI_BASE
|
|
107
|
+
if "ruff" in self.extras:
|
|
108
|
+
ci += GITHUB_ACTIONS_CI_RUFF_STEP
|
|
109
|
+
if "pytest" in self.extras:
|
|
110
|
+
ci += GITHUB_ACTIONS_CI_PYTEST_STEP
|
|
111
|
+
(workflows_path / "ci.yml").write_text(ci, encoding="utf-8")
|
|
112
|
+
|
|
113
|
+
# Write .gitkeep into chroma_db/ so git tracks the directory
|
|
114
|
+
# but the actual DB files are gitignored
|
|
115
|
+
gitkeep = project_path / "chroma_db" / ".gitkeep"
|
|
116
|
+
gitkeep.write_text("", encoding="utf-8")
|
|
117
|
+
|
|
118
|
+
gitignore_path = project_path / ".gitignore"
|
|
119
|
+
current_gitignore = gitignore_path.read_text(encoding="utf-8")
|
|
120
|
+
rag_ignore_rules = "\n# RAG vector database\nchroma_db/*\n!chroma_db/.gitkeep\n"
|
|
121
|
+
if "chroma_db/*" not in current_gitignore:
|
|
122
|
+
gitignore_path.write_text(
|
|
123
|
+
current_gitignore + rag_ignore_rules, encoding="utf-8"
|
|
124
|
+
)
|