spawnio 1.0.7__tar.gz → 1.0.9__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.
- spawnio-1.0.9/CONTRIBUTING.md +178 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/PKG-INFO +63 -15
- {spawnio-1.0.7 → spawnio-1.0.9}/README.md +62 -14
- spawnio-1.0.9/docs/architecture.md +257 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/docs/changelog.md +34 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/docs/commands.md +112 -36
- {spawnio-1.0.7 → spawnio-1.0.9}/docs/getting-started.md +24 -3
- {spawnio-1.0.7 → spawnio-1.0.9}/pyproject.toml +13 -1
- spawnio-1.0.9/src/spawn/__init__.py +6 -0
- spawnio-1.0.9/src/spawn/cli/app.py +362 -0
- spawnio-1.0.9/src/spawn/cli/errors.py +29 -0
- spawnio-1.0.9/src/spawn/cli/noninteractive.py +125 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/cli/prompts.py +47 -43
- spawnio-1.0.9/src/spawn/core/exceptions.py +50 -0
- spawnio-1.0.9/src/spawn/core/models.py +58 -0
- spawnio-1.0.7/src/spawn/cli/noninteractive.py → spawnio-1.0.9/src/spawn/core/planning.py +39 -84
- spawnio-1.0.9/src/spawn/core/project.py +59 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/core/registry.py +85 -16
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/generators/custom_structure.py +60 -39
- spawnio-1.0.9/src/spawn/generators/destination.py +66 -0
- spawnio-1.0.9/src/spawn/generators/metadata.py +45 -0
- spawnio-1.0.9/src/spawn/generators/pipeline.py +32 -0
- spawnio-1.0.9/src/spawn/generators/project_files.py +191 -0
- spawnio-1.0.9/src/spawn/generators/project_generator.py +132 -0
- spawnio-1.0.9/src/spawn/github/exceptions.py +5 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/github/publisher.py +6 -15
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/github/validators.py +1 -4
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/agent/__init__.py +48 -46
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/agent/content.py +13 -12
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/automation/__init__.py +2 -7
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/backend_api/__init__.py +2 -4
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/chatbot/__init__.py +84 -73
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/chatbot/content.py +15 -13
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/cli_application/__init__.py +17 -10
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/__init__.py +5 -12
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/analysis/__init__.py +7 -6
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/analysis/content.py +1 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/dashboard/__init__.py +7 -6
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/dashboard/content.py +1 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/etl/__init__.py +9 -8
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/etl/content.py +1 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/ml/__init__.py +8 -7
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/data_project/ml/content.py +1 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/mcp_server/__init__.py +6 -6
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/rag/__init__.py +17 -17
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/rag/content.py +1 -0
- spawnio-1.0.9/src/spawn/templates/shared_content.py +184 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/doctor.py +43 -39
- spawnio-1.0.9/src/spawn/utils/doctor_fix.py +226 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/git.py +32 -17
- spawnio-1.0.9/src/spawn/utils/redact.py +8 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/success.py +12 -7
- spawnio-1.0.9/src/spawn/utils/theme.py +25 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/uv.py +5 -9
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/validators.py +8 -5
- spawnio-1.0.9/tests/conftest.py +46 -0
- spawnio-1.0.9/tests/fixtures/__init__.py +0 -0
- spawnio-1.0.9/tests/fixtures/archetypes.py +11 -0
- spawnio-1.0.9/tests/fixtures/static/broken_meta/.spawn/meta.json +1 -0
- spawnio-1.0.9/tests/fixtures/static/meta_unknown_intent/.spawn/meta.json +11 -0
- spawnio-1.0.9/tests/fixtures/static/non_spawn_python_repo/pyproject.toml +3 -0
- spawnio-1.0.9/tests/fixtures/static/non_spawn_python_repo/src/pkg/__init__.py +1 -0
- spawnio-1.0.9/tests/fixtures/static/non_spawn_python_repo/tests/test_x.py +2 -0
- spawnio-1.0.9/tests/fixtures/trees/agent.txt +20 -0
- spawnio-1.0.9/tests/fixtures/trees/automation.txt +20 -0
- spawnio-1.0.9/tests/fixtures/trees/backend-api.txt +16 -0
- spawnio-1.0.9/tests/fixtures/trees/chatbot.txt +22 -0
- spawnio-1.0.9/tests/fixtures/trees/cli.txt +12 -0
- spawnio-1.0.9/tests/fixtures/trees/custom.txt +4 -0
- spawnio-1.0.9/tests/fixtures/trees/data.txt +12 -0
- spawnio-1.0.9/tests/fixtures/trees/mcp.txt +11 -0
- spawnio-1.0.9/tests/fixtures/trees/rag.txt +21 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_agent_generator.py +15 -9
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_agent_template.py +22 -14
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_app.py +170 -25
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_automation_generator.py +6 -3
- spawnio-1.0.9/tests/test_boundaries.py +35 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_chatbot_generator.py +43 -22
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_chatbot_template.py +136 -105
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_cli_application_generator.py +106 -33
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_cli_application_template.py +13 -6
- spawnio-1.0.9/tests/test_create_flags.py +203 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_custom_structure.py +123 -47
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_custom_structure_integration.py +33 -14
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_analysis.py +9 -7
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_dashboard.py +5 -3
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_etl.py +5 -3
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_gitignore.py +16 -8
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_data_project_ml.py +5 -3
- spawnio-1.0.9/tests/test_destination.py +238 -0
- spawnio-1.0.9/tests/test_docs.py +42 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_doctor.py +54 -23
- spawnio-1.0.9/tests/test_doctor_fix.py +223 -0
- spawnio-1.0.9/tests/test_errors.py +219 -0
- spawnio-1.0.9/tests/test_fixtures.py +158 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_generator.py +213 -50
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_git.py +1 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_github_publisher.py +7 -21
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_github_validators.py +5 -15
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_mcp_server_generator.py +10 -6
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_models.py +48 -4
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_noninteractive.py +59 -12
- spawnio-1.0.9/tests/test_pipeline.py +135 -0
- spawnio-1.0.9/tests/test_planning.py +160 -0
- spawnio-1.0.9/tests/test_project.py +88 -0
- spawnio-1.0.9/tests/test_project_files.py +371 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_prompts.py +174 -81
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_rag_generator.py +15 -8
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_rag_template.py +23 -8
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_registry.py +60 -2
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_templates.py +15 -5
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_uv.py +1 -3
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_validators.py +13 -5
- spawnio-1.0.7/.github/workflows/ci.yml +0 -29
- spawnio-1.0.7/.github/workflows/publish.yml +0 -24
- spawnio-1.0.7/.python-version +0 -1
- spawnio-1.0.7/assets/preview.png +0 -0
- spawnio-1.0.7/docs/architecture.md +0 -194
- spawnio-1.0.7/src/spawn/__init__.py +0 -6
- spawnio-1.0.7/src/spawn/cli/app.py +0 -217
- spawnio-1.0.7/src/spawn/core/exceptions.py +0 -7
- spawnio-1.0.7/src/spawn/core/models.py +0 -21
- spawnio-1.0.7/src/spawn/generators/project_generator.py +0 -115
- spawnio-1.0.7/src/spawn/github/exceptions.py +0 -5
- spawnio-1.0.7/src/spawn/templates/shared_content.py +0 -89
- spawnio-1.0.7/src/spawn/utils/theme.py +0 -25
- spawnio-1.0.7/uv.lock +0 -218
- {spawnio-1.0.7 → spawnio-1.0.9}/.gitignore +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/LICENSE +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/cli/__init__.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/core/__init__.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/generators/__init__.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/github/__init__.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/__init__.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/automation/content.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/backend_api/content.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/base.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/cli_application/content.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/templates/mcp_server/content.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/__init__.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/banner.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/src/spawn/utils/console.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_automation_template.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_console.py +0 -0
- {spawnio-1.0.7 → spawnio-1.0.9}/tests/test_mcp_server_template.py +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Contributing to spawnio
|
|
2
|
+
|
|
3
|
+
Solo-maintained, but PRs are welcome. Here's what you need to know.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Python 3.12+ (`uv python install 3.12` if using uv)
|
|
10
|
+
- [uv](https://github.com/astral-sh/uv) installed
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git clone https://github.com/Abhiix0/Spawn.git
|
|
18
|
+
cd Spawn
|
|
19
|
+
uv sync --all-groups
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Running tests
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
uv run pytest
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
With coverage:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv run pytest --cov=src/spawn --cov-report=term-missing
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Testing and fixtures
|
|
39
|
+
|
|
40
|
+
- **Factory:** the `spawn_project` fixture in `tests/conftest.py` generates a project offline: `spawn_project("backend-api", framework="fastapi")` returns its `Path`. The `no_toolchain` fixture stubs git, uv and package installs.
|
|
41
|
+
- **Golden trees:** `tests/fixtures/trees/<archetype>.txt` lists every file of a generated archetype. After an intentional output change, regenerate with `SPAWN_UPDATE_TREES=1 uv run pytest tests/test_fixtures.py` and review the diff.
|
|
42
|
+
- **Offline rule:** tests must not use the network, real `git` or real `uv`; use `no_toolchain`.
|
|
43
|
+
- **Adding an archetype:** add an entry to `tests/fixtures/archetypes.py`, run once with `SPAWN_UPDATE_TREES=1` to create its golden tree, and review it.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Linting and formatting
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv run ruff check .
|
|
51
|
+
uv run ruff format .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Both must pass before opening a PR. CI enforces this.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Adding a new template
|
|
59
|
+
|
|
60
|
+
Templates follow a consistent three-file pattern. MCP Server (`src/spawn/templates/mcp_server/`) is the cleanest minimal example to copy from.
|
|
61
|
+
|
|
62
|
+
### 1. Create the template package
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
src/spawn/templates/<your_slug>/
|
|
66
|
+
__init__.py # MyTemplate(BaseTemplate) class
|
|
67
|
+
content.py # string constants + make_readme() + make_agents_md()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**`content.py`** holds all file content as triple-quoted strings with `{project_name}` placeholders (resolved later via `.format_map(context)`). Export `make_readme()` and `make_agents_md()` as functions that return the formatted string — these are called by `BaseTemplate` machinery automatically.
|
|
71
|
+
|
|
72
|
+
**`__init__.py`** subclasses `BaseTemplate`:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
class MyTemplate(BaseTemplate):
|
|
76
|
+
def __init__(self, extras: list[str] | None = None) -> None:
|
|
77
|
+
self.extras = extras or []
|
|
78
|
+
super().__init__(
|
|
79
|
+
name="My Template",
|
|
80
|
+
folders=["src", "tests"],
|
|
81
|
+
starter_files=[
|
|
82
|
+
("src/__init__.py", INIT_CONTENT),
|
|
83
|
+
("src/main.py", MAIN_CONTENT),
|
|
84
|
+
(".env.example", ENV_CONTENT),
|
|
85
|
+
],
|
|
86
|
+
next_steps=["cd {project_name}", "uv run python -m src.main"],
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def get_readme_content(self, context: dict) -> str | None:
|
|
90
|
+
return make_readme().format_map(context)
|
|
91
|
+
|
|
92
|
+
def get_agents_md_content(self, context: dict) -> str | None:
|
|
93
|
+
return make_agents_md().format_map(context)
|
|
94
|
+
|
|
95
|
+
def get_dependencies(self) -> list[str]:
|
|
96
|
+
base = ["some-package"]
|
|
97
|
+
if "pytest" in self.extras:
|
|
98
|
+
base.append("pytest")
|
|
99
|
+
return base
|
|
100
|
+
|
|
101
|
+
def post_install(self, project_path: Path) -> None:
|
|
102
|
+
# Write pyproject.toml sections, CI workflows, etc. as needed.
|
|
103
|
+
pass
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If your template needs framework or provider selection, look at `ChatbotTemplate` or `AgentTemplate` — those accept `framework` and `provider` constructor args and use `get_supported_providers()` to filter the provider list per framework.
|
|
107
|
+
|
|
108
|
+
### 2. Register in `src/spawn/core/registry.py`
|
|
109
|
+
|
|
110
|
+
Add an import and a `TemplateMetadata` entry to `TEMPLATES`:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from spawn.templates.my_template import MyTemplate
|
|
114
|
+
|
|
115
|
+
TEMPLATES = {
|
|
116
|
+
# ... existing entries ...
|
|
117
|
+
"my-slug": TemplateMetadata(
|
|
118
|
+
slug="my-slug",
|
|
119
|
+
display_name="My Template",
|
|
120
|
+
description="One-line description shown in spawn doctor output",
|
|
121
|
+
template_class=MyTemplate,
|
|
122
|
+
available_extras=["ruff", "pytest", "github-actions"],
|
|
123
|
+
# available_frameworks, available_providers, available_cli_types,
|
|
124
|
+
# available_data_types — only set the fields your template uses.
|
|
125
|
+
),
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`instantiate_template()` inspects the constructor signature and forwards only the fields the class accepts, so no changes to that function are needed.
|
|
130
|
+
|
|
131
|
+
### 3. Write tests
|
|
132
|
+
|
|
133
|
+
Add two test files mirroring the existing pattern:
|
|
134
|
+
|
|
135
|
+
| File | What to test |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `tests/test_<slug>_template.py` | Template constants, `get_dependencies()`, `get_readme_content()`, `py_compile` on each Python starter file, no unescaped braces |
|
|
138
|
+
| `tests/test_<slug>_generator.py` | `generate_project(config)` (or `ProjectGenerator().generate()`) with mocked uv/git/install, directory structure, README content, `.spawn/meta.json` fields |
|
|
139
|
+
|
|
140
|
+
See `tests/test_mcp_server_template.py` and `tests/test_mcp_server_generator.py` for the exact mock patterns (`_mock_uv_and_install()` context manager, `_cfg()` helper, `patch.object(MyTemplate, "post_install")`).
|
|
141
|
+
|
|
142
|
+
Also update `tests/test_registry.py`: increment the `len(slugs) == N` assertion and add `assert "my-slug" in slugs`.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Branch and commit conventions
|
|
147
|
+
|
|
148
|
+
The git log uses a lightweight conventional-commits style — prefix commits with `feat:`, `fix:`, `docs:`, or `chore:` and use the imperative mood in the subject line:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
feat: add <slug> template
|
|
152
|
+
fix: handle edge case in parse_structure
|
|
153
|
+
docs: update CONTRIBUTING.md
|
|
154
|
+
chore: bump version to 1.0.8
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Branch off `main`, use a short descriptive name (`feat/my-template`, `fix/windows-path`, etc.).
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## PR expectations
|
|
162
|
+
|
|
163
|
+
- All existing tests must pass (`uv run pytest`).
|
|
164
|
+
- New templates require both a `_template` and a `_generator` test file.
|
|
165
|
+
- `uv run ruff check .` and `uv run ruff format --check .` must be clean.
|
|
166
|
+
- CI (`.github/workflows/ci.yml`) must be green.
|
|
167
|
+
- Keep PRs focused — one template or fix per PR.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Reporting issues / asking questions
|
|
172
|
+
|
|
173
|
+
GitHub Issues are currently **restricted** on this repo. To reach the maintainer:
|
|
174
|
+
|
|
175
|
+
- Open a [GitHub Discussion](https://github.com/Abhiix0/Spawn/discussions) if Discussions are enabled.
|
|
176
|
+
- Otherwise, leave a comment on an existing PR or tag `@Abhiix0` in your PR description.
|
|
177
|
+
|
|
178
|
+
If you hit a bug that's blocking you, a PR with a failing test that reproduces it is a faster path to a fix than waiting for issues to be opened.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: spawnio
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.9
|
|
4
4
|
Summary: Spawn a ready-to-use Python project in seconds
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -88,6 +88,7 @@ It's repetitive. It's inconsistent. And you haven't written a single line of *re
|
|
|
88
88
|
| **Arrow-key menus** | Every prompt in `spawn create` is arrow-key/spacebar driven, not typed numbers |
|
|
89
89
|
| **GitHub publishing** | Connects your project to an existing GitHub repo and pushes the initial commit |
|
|
90
90
|
| **spawn doctor** | Scores your project's health out of 100, with per-category breakdowns and a prioritized next step |
|
|
91
|
+
| **spawn doctor --fix** | Fixes missing files and config automatically — never overwrites, never installs packages |
|
|
91
92
|
|
|
92
93
|
---
|
|
93
94
|
|
|
@@ -143,7 +144,7 @@ Running `spawn` with no arguments shows the banner, the installed version, and t
|
|
|
143
144
|
|
|
144
145
|
```
|
|
145
146
|
SPAWN — scaffold your next project
|
|
146
|
-
v1.0.
|
|
147
|
+
v1.0.9
|
|
147
148
|
|
|
148
149
|
Commands
|
|
149
150
|
create Scaffold a new project
|
|
@@ -190,7 +191,15 @@ Use the arrow keys to move, Enter to select — the same pattern every prompt in
|
|
|
190
191
|
|
|
191
192
|
**Step 3 — Additional prompts** *(template-dependent — framework, provider, project type, and/or extras, depending on what you picked. See [Project Templates](#project-templates) below for each one's exact flow.)*
|
|
192
193
|
|
|
193
|
-
**Step 4 —
|
|
194
|
+
**Step 4 — License**
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
? Choose a license (Use arrow keys)
|
|
198
|
+
» MIT
|
|
199
|
+
None
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Step 5 — Git**
|
|
194
203
|
|
|
195
204
|
```
|
|
196
205
|
Initialize Git? [Y/n]: Y
|
|
@@ -253,9 +262,11 @@ my-api/
|
|
|
253
262
|
● pytest
|
|
254
263
|
○ docker
|
|
255
264
|
○ github-actions
|
|
265
|
+
○ pre-commit
|
|
266
|
+
○ mypy
|
|
256
267
|
```
|
|
257
268
|
|
|
258
|
-
**Available extras:** `ruff` `pytest` `docker` `github-actions`
|
|
269
|
+
**Available extras:** `ruff` `pytest` `docker` `github-actions` `pre-commit` `mypy`
|
|
259
270
|
|
|
260
271
|
**Run it:**
|
|
261
272
|
|
|
@@ -306,9 +317,11 @@ my-cli/
|
|
|
306
317
|
● ruff
|
|
307
318
|
● pytest
|
|
308
319
|
○ github-actions
|
|
320
|
+
○ pre-commit
|
|
321
|
+
○ mypy
|
|
309
322
|
```
|
|
310
323
|
|
|
311
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
324
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
312
325
|
|
|
313
326
|
**Run it:**
|
|
314
327
|
|
|
@@ -345,9 +358,11 @@ my-automation/
|
|
|
345
358
|
● ruff
|
|
346
359
|
● pytest
|
|
347
360
|
○ github-actions
|
|
361
|
+
○ pre-commit
|
|
362
|
+
○ mypy
|
|
348
363
|
```
|
|
349
364
|
|
|
350
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
365
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
351
366
|
|
|
352
367
|
**Run it:**
|
|
353
368
|
|
|
@@ -397,9 +412,11 @@ my-chatbot/
|
|
|
397
412
|
● pytest
|
|
398
413
|
○ rich
|
|
399
414
|
○ github-actions
|
|
415
|
+
○ pre-commit
|
|
416
|
+
○ mypy
|
|
400
417
|
```
|
|
401
418
|
|
|
402
|
-
**Available extras:** `ruff` `pytest` `rich` `github-actions`
|
|
419
|
+
**Available extras:** `ruff` `pytest` `rich` `github-actions` `pre-commit` `mypy`
|
|
403
420
|
|
|
404
421
|
**Run it:**
|
|
405
422
|
|
|
@@ -447,11 +464,13 @@ my-agent/
|
|
|
447
464
|
● ruff
|
|
448
465
|
● pytest
|
|
449
466
|
○ github-actions
|
|
467
|
+
○ pre-commit
|
|
468
|
+
○ mypy
|
|
450
469
|
```
|
|
451
470
|
|
|
452
471
|
> If you pick `openai-agents`, only `openai` and `openrouter` appear as provider choices — the list is filtered per framework.
|
|
453
472
|
|
|
454
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
473
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
455
474
|
|
|
456
475
|
**Run it:**
|
|
457
476
|
|
|
@@ -492,11 +511,13 @@ my-rag/
|
|
|
492
511
|
● ruff
|
|
493
512
|
● pytest
|
|
494
513
|
○ github-actions
|
|
514
|
+
○ pre-commit
|
|
515
|
+
○ mypy
|
|
495
516
|
```
|
|
496
517
|
|
|
497
518
|
RAG System uses a fixed stack — **LlamaIndex + ChromaDB + OpenAI** — so there's no framework or provider prompt, unlike Chatbot and Agent. On first run, it automatically ingests documents from `data/` into a local ChromaDB index, then lets you ask questions against them. Requires an `OPENAI_API_KEY` (used for both the LLM and embeddings).
|
|
498
519
|
|
|
499
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
520
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
500
521
|
|
|
501
522
|
**Run it:**
|
|
502
523
|
|
|
@@ -540,9 +561,11 @@ my-data-project/
|
|
|
540
561
|
● ruff
|
|
541
562
|
● pytest
|
|
542
563
|
○ github-actions
|
|
564
|
+
○ pre-commit
|
|
565
|
+
○ mypy
|
|
543
566
|
```
|
|
544
567
|
|
|
545
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
568
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
546
569
|
|
|
547
570
|
**Run it:**
|
|
548
571
|
|
|
@@ -586,11 +609,13 @@ my-mcp-server/
|
|
|
586
609
|
● ruff
|
|
587
610
|
● pytest
|
|
588
611
|
○ github-actions
|
|
612
|
+
○ pre-commit
|
|
613
|
+
○ mypy
|
|
589
614
|
```
|
|
590
615
|
|
|
591
616
|
MCP Server uses a fixed stack — the official `mcp` Python SDK's `FastMCP` — so there's no framework or provider prompt, the same as RAG System.
|
|
592
617
|
|
|
593
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
618
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
594
619
|
|
|
595
620
|
**Run it:**
|
|
596
621
|
|
|
@@ -641,6 +666,7 @@ Dependencies (comma separated, optional): fastapi, uvicorn
|
|
|
641
666
|
● Pytest
|
|
642
667
|
○ Pre-commit
|
|
643
668
|
○ Dockerfile
|
|
669
|
+
○ Mypy
|
|
644
670
|
|
|
645
671
|
Additional ignore patterns (optional, comma separated): data/, *.csv
|
|
646
672
|
|
|
@@ -654,7 +680,7 @@ Proceed? [Y/n]: Y
|
|
|
654
680
|
|
|
655
681
|
**The Dependencies prompt** (shown only when uv is enabled) installs packages immediately via `uv add`.
|
|
656
682
|
|
|
657
|
-
**The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, and/or `
|
|
683
|
+
**The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, `Dockerfile`, and/or `[tool.mypy]` in `pyproject.toml`.
|
|
658
684
|
|
|
659
685
|
### Non-Interactive Mode
|
|
660
686
|
|
|
@@ -663,7 +689,7 @@ Skip all prompts by passing flags directly or pointing to a JSON config file.
|
|
|
663
689
|
**Using flags:**
|
|
664
690
|
|
|
665
691
|
```bash
|
|
666
|
-
spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --git
|
|
692
|
+
spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --license mit --git
|
|
667
693
|
```
|
|
668
694
|
|
|
669
695
|
**Using a config file:**
|
|
@@ -674,6 +700,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
|
|
|
674
700
|
"template": "backend-api",
|
|
675
701
|
"framework": "fastapi",
|
|
676
702
|
"extras": ["ruff", "pytest"],
|
|
703
|
+
"license": "mit",
|
|
677
704
|
"git": true,
|
|
678
705
|
"uv": true
|
|
679
706
|
}
|
|
@@ -683,7 +710,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
|
|
|
683
710
|
spawn create --config spawn.json
|
|
684
711
|
```
|
|
685
712
|
|
|
686
|
-
`--config` takes precedence over individual flags. Add `--dry-run` to either form to validate the config and print it without creating any files.
|
|
713
|
+
`--config` takes precedence over individual flags (an explicit `--no-git`/`--no-uv` is ignored with a warning). Add `--dry-run` to either form to validate the config and print it without creating any files.
|
|
687
714
|
|
|
688
715
|
> Custom Structure is interactive-only in this version.
|
|
689
716
|
|
|
@@ -741,11 +768,30 @@ spawn doctor ./path/to/project
|
|
|
741
768
|
|
|
742
769
|
Checks span six categories — Documentation, Version Control, Configuration, Testing, Automation, and Code Quality (Ruff, type checking, pre-commit) — all filesystem-based, nothing is executed or sent over the network.
|
|
743
770
|
|
|
771
|
+
#### Automatic Remediation with `--fix`
|
|
772
|
+
|
|
773
|
+
`spawn doctor --fix` creates missing files and config automatically. It **never overwrites** pre-existing files and **never installs packages** directly (instead printing `uv add` commands for optional tools).
|
|
774
|
+
|
|
775
|
+
```bash
|
|
776
|
+
# Automatically create missing files and config
|
|
777
|
+
spawn doctor --fix
|
|
778
|
+
spawn doctor ./path/to/project --fix
|
|
779
|
+
|
|
780
|
+
# Preview what would be created without touching disk
|
|
781
|
+
spawn doctor --fix --dry-run
|
|
782
|
+
|
|
783
|
+
# Run non-interactively without the confirmation prompt
|
|
784
|
+
spawn doctor --fix --yes
|
|
785
|
+
|
|
786
|
+
# Also add an MIT license if missing
|
|
787
|
+
spawn doctor --fix --license mit
|
|
788
|
+
```
|
|
789
|
+
|
|
744
790
|
### `spawn version`
|
|
745
791
|
|
|
746
792
|
```bash
|
|
747
793
|
spawn version
|
|
748
|
-
# → Spawn v1.0.
|
|
794
|
+
# → Spawn v1.0.9
|
|
749
795
|
```
|
|
750
796
|
|
|
751
797
|
### Publish to GitHub
|
|
@@ -779,6 +825,8 @@ All tests should pass. If they don't, please [open an issue](https://github.com/
|
|
|
779
825
|
|
|
780
826
|
| Version | Highlight |
|
|
781
827
|
|---|---|
|
|
828
|
+
| **v1.0.9** | Core hardening: documented exit-code contract (generation, toolchain and publish failures exit non-zero), `--no-uv` honored for templates (file-only extras still written), path-traversal protection for custom structures, `read_project_metadata` extension boundary |
|
|
829
|
+
| **v1.0.8** | `spawn doctor --fix` (`--dry-run`, `--yes`, `--license`), `--license` flag and prompt on `create`, `CHANGELOG.md` generated for every project, `pre-commit` and `mypy` extras across all templates, Custom Structure Mypy option |
|
|
782
830
|
| **v1.0.7** | Fixed UTF-8 console crash on Windows when stdout is redirected/piped, added Windows reserved device name validation (`CON`, `PRN`, `AUX`, `NUL`, `COM1`–`9`, `LPT1`–`9`), clarified Python 3.12 requirement |
|
|
783
831
|
| **v1.0.6** | Removed duplicate banner from `spawn create`; `spawn` alone now shows the banner and command overview |
|
|
784
832
|
| **v1.0.5** | Published to PyPI as `spawnio`; arrow-key selection menus, no-args banner, consistent Ctrl+C handling |
|
|
@@ -77,6 +77,7 @@ It's repetitive. It's inconsistent. And you haven't written a single line of *re
|
|
|
77
77
|
| **Arrow-key menus** | Every prompt in `spawn create` is arrow-key/spacebar driven, not typed numbers |
|
|
78
78
|
| **GitHub publishing** | Connects your project to an existing GitHub repo and pushes the initial commit |
|
|
79
79
|
| **spawn doctor** | Scores your project's health out of 100, with per-category breakdowns and a prioritized next step |
|
|
80
|
+
| **spawn doctor --fix** | Fixes missing files and config automatically — never overwrites, never installs packages |
|
|
80
81
|
|
|
81
82
|
---
|
|
82
83
|
|
|
@@ -132,7 +133,7 @@ Running `spawn` with no arguments shows the banner, the installed version, and t
|
|
|
132
133
|
|
|
133
134
|
```
|
|
134
135
|
SPAWN — scaffold your next project
|
|
135
|
-
v1.0.
|
|
136
|
+
v1.0.9
|
|
136
137
|
|
|
137
138
|
Commands
|
|
138
139
|
create Scaffold a new project
|
|
@@ -179,7 +180,15 @@ Use the arrow keys to move, Enter to select — the same pattern every prompt in
|
|
|
179
180
|
|
|
180
181
|
**Step 3 — Additional prompts** *(template-dependent — framework, provider, project type, and/or extras, depending on what you picked. See [Project Templates](#project-templates) below for each one's exact flow.)*
|
|
181
182
|
|
|
182
|
-
**Step 4 —
|
|
183
|
+
**Step 4 — License**
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
? Choose a license (Use arrow keys)
|
|
187
|
+
» MIT
|
|
188
|
+
None
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Step 5 — Git**
|
|
183
192
|
|
|
184
193
|
```
|
|
185
194
|
Initialize Git? [Y/n]: Y
|
|
@@ -242,9 +251,11 @@ my-api/
|
|
|
242
251
|
● pytest
|
|
243
252
|
○ docker
|
|
244
253
|
○ github-actions
|
|
254
|
+
○ pre-commit
|
|
255
|
+
○ mypy
|
|
245
256
|
```
|
|
246
257
|
|
|
247
|
-
**Available extras:** `ruff` `pytest` `docker` `github-actions`
|
|
258
|
+
**Available extras:** `ruff` `pytest` `docker` `github-actions` `pre-commit` `mypy`
|
|
248
259
|
|
|
249
260
|
**Run it:**
|
|
250
261
|
|
|
@@ -295,9 +306,11 @@ my-cli/
|
|
|
295
306
|
● ruff
|
|
296
307
|
● pytest
|
|
297
308
|
○ github-actions
|
|
309
|
+
○ pre-commit
|
|
310
|
+
○ mypy
|
|
298
311
|
```
|
|
299
312
|
|
|
300
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
313
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
301
314
|
|
|
302
315
|
**Run it:**
|
|
303
316
|
|
|
@@ -334,9 +347,11 @@ my-automation/
|
|
|
334
347
|
● ruff
|
|
335
348
|
● pytest
|
|
336
349
|
○ github-actions
|
|
350
|
+
○ pre-commit
|
|
351
|
+
○ mypy
|
|
337
352
|
```
|
|
338
353
|
|
|
339
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
354
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
340
355
|
|
|
341
356
|
**Run it:**
|
|
342
357
|
|
|
@@ -386,9 +401,11 @@ my-chatbot/
|
|
|
386
401
|
● pytest
|
|
387
402
|
○ rich
|
|
388
403
|
○ github-actions
|
|
404
|
+
○ pre-commit
|
|
405
|
+
○ mypy
|
|
389
406
|
```
|
|
390
407
|
|
|
391
|
-
**Available extras:** `ruff` `pytest` `rich` `github-actions`
|
|
408
|
+
**Available extras:** `ruff` `pytest` `rich` `github-actions` `pre-commit` `mypy`
|
|
392
409
|
|
|
393
410
|
**Run it:**
|
|
394
411
|
|
|
@@ -436,11 +453,13 @@ my-agent/
|
|
|
436
453
|
● ruff
|
|
437
454
|
● pytest
|
|
438
455
|
○ github-actions
|
|
456
|
+
○ pre-commit
|
|
457
|
+
○ mypy
|
|
439
458
|
```
|
|
440
459
|
|
|
441
460
|
> If you pick `openai-agents`, only `openai` and `openrouter` appear as provider choices — the list is filtered per framework.
|
|
442
461
|
|
|
443
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
462
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
444
463
|
|
|
445
464
|
**Run it:**
|
|
446
465
|
|
|
@@ -481,11 +500,13 @@ my-rag/
|
|
|
481
500
|
● ruff
|
|
482
501
|
● pytest
|
|
483
502
|
○ github-actions
|
|
503
|
+
○ pre-commit
|
|
504
|
+
○ mypy
|
|
484
505
|
```
|
|
485
506
|
|
|
486
507
|
RAG System uses a fixed stack — **LlamaIndex + ChromaDB + OpenAI** — so there's no framework or provider prompt, unlike Chatbot and Agent. On first run, it automatically ingests documents from `data/` into a local ChromaDB index, then lets you ask questions against them. Requires an `OPENAI_API_KEY` (used for both the LLM and embeddings).
|
|
487
508
|
|
|
488
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
509
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
489
510
|
|
|
490
511
|
**Run it:**
|
|
491
512
|
|
|
@@ -529,9 +550,11 @@ my-data-project/
|
|
|
529
550
|
● ruff
|
|
530
551
|
● pytest
|
|
531
552
|
○ github-actions
|
|
553
|
+
○ pre-commit
|
|
554
|
+
○ mypy
|
|
532
555
|
```
|
|
533
556
|
|
|
534
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
557
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
535
558
|
|
|
536
559
|
**Run it:**
|
|
537
560
|
|
|
@@ -575,11 +598,13 @@ my-mcp-server/
|
|
|
575
598
|
● ruff
|
|
576
599
|
● pytest
|
|
577
600
|
○ github-actions
|
|
601
|
+
○ pre-commit
|
|
602
|
+
○ mypy
|
|
578
603
|
```
|
|
579
604
|
|
|
580
605
|
MCP Server uses a fixed stack — the official `mcp` Python SDK's `FastMCP` — so there's no framework or provider prompt, the same as RAG System.
|
|
581
606
|
|
|
582
|
-
**Available extras:** `ruff` `pytest` `github-actions`
|
|
607
|
+
**Available extras:** `ruff` `pytest` `github-actions` `pre-commit` `mypy`
|
|
583
608
|
|
|
584
609
|
**Run it:**
|
|
585
610
|
|
|
@@ -630,6 +655,7 @@ Dependencies (comma separated, optional): fastapi, uvicorn
|
|
|
630
655
|
● Pytest
|
|
631
656
|
○ Pre-commit
|
|
632
657
|
○ Dockerfile
|
|
658
|
+
○ Mypy
|
|
633
659
|
|
|
634
660
|
Additional ignore patterns (optional, comma separated): data/, *.csv
|
|
635
661
|
|
|
@@ -643,7 +669,7 @@ Proceed? [Y/n]: Y
|
|
|
643
669
|
|
|
644
670
|
**The Dependencies prompt** (shown only when uv is enabled) installs packages immediately via `uv add`.
|
|
645
671
|
|
|
646
|
-
**The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, and/or `
|
|
672
|
+
**The Optional Setup menu** installs dev tools via `uv add --dev` and generates their config files: `ruff.toml`, `tests/__init__.py`, `.pre-commit-config.yaml`, `Dockerfile`, and/or `[tool.mypy]` in `pyproject.toml`.
|
|
647
673
|
|
|
648
674
|
### Non-Interactive Mode
|
|
649
675
|
|
|
@@ -652,7 +678,7 @@ Skip all prompts by passing flags directly or pointing to a JSON config file.
|
|
|
652
678
|
**Using flags:**
|
|
653
679
|
|
|
654
680
|
```bash
|
|
655
|
-
spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --git
|
|
681
|
+
spawn create --name my-api --template backend-api --framework fastapi --extras ruff,pytest --license mit --git
|
|
656
682
|
```
|
|
657
683
|
|
|
658
684
|
**Using a config file:**
|
|
@@ -663,6 +689,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
|
|
|
663
689
|
"template": "backend-api",
|
|
664
690
|
"framework": "fastapi",
|
|
665
691
|
"extras": ["ruff", "pytest"],
|
|
692
|
+
"license": "mit",
|
|
666
693
|
"git": true,
|
|
667
694
|
"uv": true
|
|
668
695
|
}
|
|
@@ -672,7 +699,7 @@ spawn create --name my-api --template backend-api --framework fastapi --extras r
|
|
|
672
699
|
spawn create --config spawn.json
|
|
673
700
|
```
|
|
674
701
|
|
|
675
|
-
`--config` takes precedence over individual flags. Add `--dry-run` to either form to validate the config and print it without creating any files.
|
|
702
|
+
`--config` takes precedence over individual flags (an explicit `--no-git`/`--no-uv` is ignored with a warning). Add `--dry-run` to either form to validate the config and print it without creating any files.
|
|
676
703
|
|
|
677
704
|
> Custom Structure is interactive-only in this version.
|
|
678
705
|
|
|
@@ -730,11 +757,30 @@ spawn doctor ./path/to/project
|
|
|
730
757
|
|
|
731
758
|
Checks span six categories — Documentation, Version Control, Configuration, Testing, Automation, and Code Quality (Ruff, type checking, pre-commit) — all filesystem-based, nothing is executed or sent over the network.
|
|
732
759
|
|
|
760
|
+
#### Automatic Remediation with `--fix`
|
|
761
|
+
|
|
762
|
+
`spawn doctor --fix` creates missing files and config automatically. It **never overwrites** pre-existing files and **never installs packages** directly (instead printing `uv add` commands for optional tools).
|
|
763
|
+
|
|
764
|
+
```bash
|
|
765
|
+
# Automatically create missing files and config
|
|
766
|
+
spawn doctor --fix
|
|
767
|
+
spawn doctor ./path/to/project --fix
|
|
768
|
+
|
|
769
|
+
# Preview what would be created without touching disk
|
|
770
|
+
spawn doctor --fix --dry-run
|
|
771
|
+
|
|
772
|
+
# Run non-interactively without the confirmation prompt
|
|
773
|
+
spawn doctor --fix --yes
|
|
774
|
+
|
|
775
|
+
# Also add an MIT license if missing
|
|
776
|
+
spawn doctor --fix --license mit
|
|
777
|
+
```
|
|
778
|
+
|
|
733
779
|
### `spawn version`
|
|
734
780
|
|
|
735
781
|
```bash
|
|
736
782
|
spawn version
|
|
737
|
-
# → Spawn v1.0.
|
|
783
|
+
# → Spawn v1.0.9
|
|
738
784
|
```
|
|
739
785
|
|
|
740
786
|
### Publish to GitHub
|
|
@@ -768,6 +814,8 @@ All tests should pass. If they don't, please [open an issue](https://github.com/
|
|
|
768
814
|
|
|
769
815
|
| Version | Highlight |
|
|
770
816
|
|---|---|
|
|
817
|
+
| **v1.0.9** | Core hardening: documented exit-code contract (generation, toolchain and publish failures exit non-zero), `--no-uv` honored for templates (file-only extras still written), path-traversal protection for custom structures, `read_project_metadata` extension boundary |
|
|
818
|
+
| **v1.0.8** | `spawn doctor --fix` (`--dry-run`, `--yes`, `--license`), `--license` flag and prompt on `create`, `CHANGELOG.md` generated for every project, `pre-commit` and `mypy` extras across all templates, Custom Structure Mypy option |
|
|
771
819
|
| **v1.0.7** | Fixed UTF-8 console crash on Windows when stdout is redirected/piped, added Windows reserved device name validation (`CON`, `PRN`, `AUX`, `NUL`, `COM1`–`9`, `LPT1`–`9`), clarified Python 3.12 requirement |
|
|
772
820
|
| **v1.0.6** | Removed duplicate banner from `spawn create`; `spawn` alone now shows the banner and command overview |
|
|
773
821
|
| **v1.0.5** | Published to PyPI as `spawnio`; arrow-key selection menus, no-args banner, consistent Ctrl+C handling |
|