spawnio 1.0.6__tar.gz → 1.0.8__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.8/.coderabbit.yaml +105 -0
- spawnio-1.0.8/.github/ISSUE_TEMPLATE/bug_report.yml +77 -0
- spawnio-1.0.8/.github/ISSUE_TEMPLATE/config.yml +5 -0
- spawnio-1.0.8/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
- spawnio-1.0.8/.github/PULL_REQUEST_TEMPLATE.md +24 -0
- spawnio-1.0.8/.github/labeler.yml +25 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/.github/workflows/ci.yml +29 -29
- spawnio-1.0.8/.github/workflows/pr-check.yml +60 -0
- spawnio-1.0.8/.github/workflows/publish.yml +24 -0
- spawnio-1.0.8/CONTRIBUTING.md +169 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/LICENSE +21 -21
- {spawnio-1.0.6 → spawnio-1.0.8}/PKG-INFO +87 -29
- {spawnio-1.0.6 → spawnio-1.0.8}/README.md +887 -829
- {spawnio-1.0.6 → spawnio-1.0.8}/docs/architecture.md +199 -194
- {spawnio-1.0.6 → spawnio-1.0.8}/docs/changelog.md +438 -405
- spawnio-1.0.8/docs/commands.md +530 -0
- spawnio-1.0.8/docs/getting-started.md +288 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/pyproject.toml +29 -28
- spawnio-1.0.8/src/spawn/__init__.py +6 -0
- spawnio-1.0.8/src/spawn/cli/app.py +374 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/cli/noninteractive.py +217 -204
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/cli/prompts.py +275 -267
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/exceptions.py +8 -7
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/models.py +22 -21
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/registry.py +221 -152
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/generators/custom_structure.py +506 -508
- spawnio-1.0.8/src/spawn/generators/project_files.py +191 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/generators/project_generator.py +131 -115
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/exceptions.py +5 -5
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/publisher.py +59 -69
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/validators.py +20 -23
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/agent/__init__.py +184 -182
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/agent/content.py +375 -374
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/automation/__init__.py +95 -100
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/automation/content.py +181 -181
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/backend_api/__init__.py +241 -243
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/backend_api/content.py +509 -509
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/base.py +58 -58
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/chatbot/__init__.py +254 -243
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/chatbot/content.py +658 -668
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/cli_application/__init__.py +218 -211
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/cli_application/content.py +512 -512
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/__init__.py +118 -125
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/analysis/__init__.py +75 -74
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/analysis/content.py +191 -190
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/dashboard/__init__.py +62 -61
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/dashboard/content.py +136 -135
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/etl/__init__.py +67 -66
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/etl/content.py +240 -239
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/ml/__init__.py +63 -62
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/ml/content.py +240 -239
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/mcp_server/__init__.py +83 -83
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/mcp_server/content.py +161 -161
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/rag/__init__.py +124 -124
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/rag/content.py +464 -463
- spawnio-1.0.8/src/spawn/templates/shared_content.py +184 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/banner.py +41 -41
- spawnio-1.0.8/src/spawn/utils/console.py +9 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/doctor.py +598 -594
- spawnio-1.0.8/src/spawn/utils/doctor_fix.py +226 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/git.py +144 -132
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/success.py +46 -47
- spawnio-1.0.8/src/spawn/utils/theme.py +25 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/uv.py +55 -61
- spawnio-1.0.8/src/spawn/utils/validators.py +30 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_agent_generator.py +239 -233
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_agent_template.py +241 -233
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_app.py +618 -471
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_automation_generator.py +245 -242
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_automation_template.py +68 -68
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_chatbot_generator.py +333 -312
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_chatbot_template.py +681 -650
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_cli_application_generator.py +297 -224
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_cli_application_template.py +197 -190
- spawnio-1.0.8/tests/test_console.py +33 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_custom_structure.py +897 -823
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_custom_structure_integration.py +155 -136
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_analysis.py +189 -187
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_dashboard.py +178 -176
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_etl.py +226 -224
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_gitignore.py +179 -171
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_ml.py +210 -208
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_doctor.py +710 -679
- spawnio-1.0.8/tests/test_doctor_fix.py +223 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_generator.py +871 -710
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_git.py +188 -187
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_github_publisher.py +135 -149
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_github_validators.py +47 -57
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_mcp_server_generator.py +138 -134
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_mcp_server_template.py +157 -157
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_models.py +70 -70
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_noninteractive.py +258 -211
- spawnio-1.0.8/tests/test_project_files.py +371 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_prompts.py +499 -406
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_rag_generator.py +237 -230
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_rag_template.py +339 -324
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_registry.py +244 -186
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_templates.py +262 -252
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_uv.py +87 -89
- {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_validators.py +123 -93
- spawnio-1.0.8/uv.lock +333 -0
- spawnio-1.0.6/docs/commands.md +0 -514
- spawnio-1.0.6/docs/getting-started.md +0 -204
- spawnio-1.0.6/src/spawn/__init__.py +0 -6
- spawnio-1.0.6/src/spawn/cli/app.py +0 -217
- spawnio-1.0.6/src/spawn/templates/shared_content.py +0 -89
- spawnio-1.0.6/src/spawn/utils/console.py +0 -3
- spawnio-1.0.6/src/spawn/utils/theme.py +0 -25
- spawnio-1.0.6/src/spawn/utils/validators.py +0 -15
- spawnio-1.0.6/uv.lock +0 -218
- {spawnio-1.0.6 → spawnio-1.0.8}/.gitignore +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/.python-version +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/assets/preview.png +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/cli/__init__.py +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/__init__.py +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/generators/__init__.py +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/__init__.py +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/__init__.py +0 -0
- {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/__init__.py +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
|
|
2
|
+
# CodeRabbit configuration for spawnio
|
|
3
|
+
# https://docs.coderabbit.ai/reference/configuration
|
|
4
|
+
#
|
|
5
|
+
# NOTE FOR MAINTAINERS: This file configures CodeRabbit's behavior once the
|
|
6
|
+
# GitHub App is installed. To activate it, install CodeRabbit at:
|
|
7
|
+
# https://github.com/apps/coderabbitai
|
|
8
|
+
# The YAML alone does nothing without the App being installed on the repo.
|
|
9
|
+
|
|
10
|
+
language: "en-US"
|
|
11
|
+
|
|
12
|
+
reviews:
|
|
13
|
+
profile: "chill"
|
|
14
|
+
|
|
15
|
+
# Auto-review settings
|
|
16
|
+
auto_review:
|
|
17
|
+
enabled: true
|
|
18
|
+
incremental: true
|
|
19
|
+
drafts: false
|
|
20
|
+
base_branches: [] # only the default branch (main)
|
|
21
|
+
|
|
22
|
+
# Walkthrough + summary in the PR comment
|
|
23
|
+
high_level_summary: true
|
|
24
|
+
high_level_summary_in_walkthrough: true
|
|
25
|
+
changed_files_summary: true
|
|
26
|
+
sequence_diagrams: true
|
|
27
|
+
|
|
28
|
+
# Do not auto-approve or request auto-merge — those are human decisions
|
|
29
|
+
# (auto_approve_reviews defaults to false — listed here for explicitness)
|
|
30
|
+
# auto_approve_reviews: false # already the default; not setting to avoid confusion
|
|
31
|
+
|
|
32
|
+
# Restrict review to the files this project actually owns
|
|
33
|
+
path_filters:
|
|
34
|
+
- "src/spawn/**"
|
|
35
|
+
- "tests/**"
|
|
36
|
+
- "!**/__pycache__/**"
|
|
37
|
+
- "!**/*.pyc"
|
|
38
|
+
- "!dist/**"
|
|
39
|
+
- "!.venv/**"
|
|
40
|
+
- "!uv.lock"
|
|
41
|
+
|
|
42
|
+
# Path-specific review instructions
|
|
43
|
+
path_instructions:
|
|
44
|
+
- path: "src/spawn/templates/**"
|
|
45
|
+
instructions: >
|
|
46
|
+
Check for cross-platform path handling. This project targets Windows
|
|
47
|
+
as a first-class platform: prefer pathlib.Path over os.path string
|
|
48
|
+
operations, avoid hardcoded forward-slashes in file paths, and flag
|
|
49
|
+
any str() coercions of Path objects that could break on Windows.
|
|
50
|
+
|
|
51
|
+
- path: "src/spawn/github/**"
|
|
52
|
+
instructions: >
|
|
53
|
+
Flag input validation and URL parsing issues. GitHub URLs must be
|
|
54
|
+
validated before use — check that repository URLs are validated
|
|
55
|
+
against the existing validators.py patterns, that user-supplied
|
|
56
|
+
strings are never interpolated directly into subprocess commands, and
|
|
57
|
+
that GitHubPublishError is raised (not a raw exception) on all failure
|
|
58
|
+
paths.
|
|
59
|
+
|
|
60
|
+
- path: "src/spawn/cli/app.py"
|
|
61
|
+
instructions: >
|
|
62
|
+
Flag function length and complexity. The create() function is known to
|
|
63
|
+
be monolithic — flag any new logic added to its body that should
|
|
64
|
+
instead live in a helper or in noninteractive.py. Prefer raising
|
|
65
|
+
SpawnError over inline console.print()+return patterns for new error
|
|
66
|
+
paths.
|
|
67
|
+
|
|
68
|
+
- path: "src/spawn/cli/**"
|
|
69
|
+
instructions: >
|
|
70
|
+
Verify that every new prompt uses _select() or _multiselect() from
|
|
71
|
+
prompts.py (questionary-based, arrow-key driven) rather than
|
|
72
|
+
typer.prompt() with a numeric choice map. typer.prompt() is only
|
|
73
|
+
acceptable for free-text inputs (project name, dependency list, etc.).
|
|
74
|
+
|
|
75
|
+
- path: "tests/**"
|
|
76
|
+
instructions: >
|
|
77
|
+
Confirm that questionary.select and questionary.checkbox are mocked
|
|
78
|
+
via patch('spawn.cli.prompts.questionary.select') and
|
|
79
|
+
patch('spawn.cli.prompts.questionary.checkbox'), not via numeric
|
|
80
|
+
typer.prompt side effects. New generator tests should use the
|
|
81
|
+
_mock_uv_and_install() context manager pattern already established
|
|
82
|
+
in the file.
|
|
83
|
+
|
|
84
|
+
# Enable the built-in Ruff tool integration (already in dev deps).
|
|
85
|
+
# NOTE: must live under reviews.tools, not top-level tools — a top-level
|
|
86
|
+
# `tools:` key is not part of the schema and is silently ignored.
|
|
87
|
+
tools:
|
|
88
|
+
ruff:
|
|
89
|
+
enabled: true
|
|
90
|
+
# Disable linters irrelevant to this pure-Python project
|
|
91
|
+
shellcheck:
|
|
92
|
+
enabled: false
|
|
93
|
+
biome:
|
|
94
|
+
enabled: false
|
|
95
|
+
hadolint:
|
|
96
|
+
enabled: false # project has no Dockerfiles in src/
|
|
97
|
+
phpstan:
|
|
98
|
+
enabled: false
|
|
99
|
+
golangci-lint:
|
|
100
|
+
enabled: false
|
|
101
|
+
swiftlint:
|
|
102
|
+
enabled: false
|
|
103
|
+
|
|
104
|
+
chat:
|
|
105
|
+
auto_reply: true
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something isn't working as expected
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Before filing, check the [open issues](https://github.com/Abhiix0/Spawn/issues)
|
|
9
|
+
and [changelog](https://github.com/Abhiix0/Spawn/blob/main/docs/changelog.md)
|
|
10
|
+
to see if this is already known.
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: description
|
|
14
|
+
attributes:
|
|
15
|
+
label: What happened?
|
|
16
|
+
description: A clear description of the bug.
|
|
17
|
+
placeholder: "When I run `spawn create`, it …"
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: repro
|
|
23
|
+
attributes:
|
|
24
|
+
label: Steps to reproduce
|
|
25
|
+
description: Minimal steps to trigger the bug.
|
|
26
|
+
placeholder: |
|
|
27
|
+
1. Run `spawn create`
|
|
28
|
+
2. Choose template …
|
|
29
|
+
3. See error …
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: expected
|
|
35
|
+
attributes:
|
|
36
|
+
label: Expected behavior
|
|
37
|
+
description: What should have happened?
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
|
|
41
|
+
- type: textarea
|
|
42
|
+
id: actual
|
|
43
|
+
attributes:
|
|
44
|
+
label: Actual behavior
|
|
45
|
+
description: What actually happened? Paste any error output or traceback here.
|
|
46
|
+
render: shell
|
|
47
|
+
validations:
|
|
48
|
+
required: true
|
|
49
|
+
|
|
50
|
+
- type: input
|
|
51
|
+
id: spawn_version
|
|
52
|
+
attributes:
|
|
53
|
+
label: Spawn version
|
|
54
|
+
description: Output of `spawn version`
|
|
55
|
+
placeholder: "Spawn v1.0.7"
|
|
56
|
+
validations:
|
|
57
|
+
required: true
|
|
58
|
+
|
|
59
|
+
- type: input
|
|
60
|
+
id: python_version
|
|
61
|
+
attributes:
|
|
62
|
+
label: Python version
|
|
63
|
+
description: Output of `python --version`
|
|
64
|
+
placeholder: "Python 3.12.3"
|
|
65
|
+
validations:
|
|
66
|
+
required: true
|
|
67
|
+
|
|
68
|
+
- type: dropdown
|
|
69
|
+
id: os
|
|
70
|
+
attributes:
|
|
71
|
+
label: Operating system
|
|
72
|
+
options:
|
|
73
|
+
- Windows
|
|
74
|
+
- macOS
|
|
75
|
+
- Linux
|
|
76
|
+
validations:
|
|
77
|
+
required: true
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a new template, command, or improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem / use case
|
|
9
|
+
description: What are you trying to do that spawnio doesn't support today?
|
|
10
|
+
placeholder: "I want to scaffold a … project but there's no template for it."
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: solution
|
|
16
|
+
attributes:
|
|
17
|
+
label: Proposed solution
|
|
18
|
+
description: What would you like to see added or changed?
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
|
|
22
|
+
- type: textarea
|
|
23
|
+
id: alternatives
|
|
24
|
+
attributes:
|
|
25
|
+
label: Alternatives considered
|
|
26
|
+
description: Any other approaches you've thought about? Fine to leave blank.
|
|
27
|
+
validations:
|
|
28
|
+
required: false
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
## Description
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR do? Be specific enough that a reviewer can understand the change without reading the diff first. -->
|
|
4
|
+
|
|
5
|
+
## Related issue
|
|
6
|
+
|
|
7
|
+
<!-- If this closes an issue: "Closes #N". If there's no issue, delete this section. -->
|
|
8
|
+
|
|
9
|
+
## Type of change
|
|
10
|
+
|
|
11
|
+
- [ ] Bug fix
|
|
12
|
+
- [ ] New feature / new template
|
|
13
|
+
- [ ] Documentation
|
|
14
|
+
- [ ] Refactor / internal cleanup
|
|
15
|
+
- [ ] CI / tooling
|
|
16
|
+
|
|
17
|
+
## Checklist
|
|
18
|
+
|
|
19
|
+
- [ ] `uv run pytest` passes locally
|
|
20
|
+
- [ ] `uv run ruff check .` is clean
|
|
21
|
+
- [ ] `uv run ruff format --check .` is clean
|
|
22
|
+
- [ ] New template PRs include both a `test_<slug>_template.py` and `test_<slug>_generator.py`
|
|
23
|
+
- [ ] `tests/test_registry.py` slug count updated (if a template was added or removed)
|
|
24
|
+
- [ ] Docs updated if the change affects user-facing behavior (README, docs/, CONTRIBUTING)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
templates:
|
|
2
|
+
- changed-files:
|
|
3
|
+
- any-glob-to-any-file: "src/spawn/templates/**"
|
|
4
|
+
|
|
5
|
+
core:
|
|
6
|
+
- changed-files:
|
|
7
|
+
- any-glob-to-any-file: "src/spawn/core/**"
|
|
8
|
+
|
|
9
|
+
cli:
|
|
10
|
+
- changed-files:
|
|
11
|
+
- any-glob-to-any-file: "src/spawn/cli/**"
|
|
12
|
+
|
|
13
|
+
docs:
|
|
14
|
+
- changed-files:
|
|
15
|
+
- any-glob-to-any-file:
|
|
16
|
+
- "docs/**"
|
|
17
|
+
- "README.md"
|
|
18
|
+
|
|
19
|
+
tests:
|
|
20
|
+
- changed-files:
|
|
21
|
+
- any-glob-to-any-file: "tests/**"
|
|
22
|
+
|
|
23
|
+
ci:
|
|
24
|
+
- changed-files:
|
|
25
|
+
- any-glob-to-any-file: ".github/**"
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v4
|
|
15
|
-
|
|
16
|
-
- name: Install uv
|
|
17
|
-
uses: astral-sh/setup-uv@v5
|
|
18
|
-
|
|
19
|
-
- name: Set up Python
|
|
20
|
-
run: uv python install 3.12
|
|
21
|
-
|
|
22
|
-
- name: Install dependencies
|
|
23
|
-
run: uv sync --all-groups
|
|
24
|
-
|
|
25
|
-
- name: Run tests
|
|
26
|
-
run: uv run pytest
|
|
27
|
-
|
|
28
|
-
- name: Run ruff
|
|
29
|
-
run: uv run ruff check .
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v5
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
run: uv python install 3.12
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: uv sync --all-groups
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: uv run pytest
|
|
27
|
+
|
|
28
|
+
- name: Run ruff
|
|
29
|
+
run: uv run ruff check .
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: PR Check
|
|
2
|
+
|
|
3
|
+
# Runs on every PR targeting main.
|
|
4
|
+
# ci.yml already runs the plain test + ruff-check pass on both push and PR.
|
|
5
|
+
# This workflow adds what ci.yml does not: coverage reporting, format check,
|
|
6
|
+
# and automatic PR labeling — so there is no duplicate test run.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
pull_request:
|
|
10
|
+
types: [opened, synchronize, reopened]
|
|
11
|
+
branches: [main]
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# Coverage + format check
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
coverage:
|
|
18
|
+
name: Coverage & Format
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v5
|
|
26
|
+
|
|
27
|
+
- name: Set up Python
|
|
28
|
+
run: uv python install 3.12
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: uv sync --all-groups
|
|
32
|
+
|
|
33
|
+
- name: Run tests with coverage
|
|
34
|
+
run: uv run pytest --cov=src/spawn --cov-report=xml --cov-report=term-missing
|
|
35
|
+
|
|
36
|
+
- name: Check formatting
|
|
37
|
+
run: uv run ruff format --check .
|
|
38
|
+
|
|
39
|
+
- name: Upload coverage report
|
|
40
|
+
uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: coverage-report
|
|
43
|
+
path: coverage.xml
|
|
44
|
+
retention-days: 7
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# Auto-labeling
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
label:
|
|
50
|
+
name: Label PR
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
permissions:
|
|
53
|
+
contents: read
|
|
54
|
+
pull-requests: write
|
|
55
|
+
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/labeler@v5
|
|
58
|
+
with:
|
|
59
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
60
|
+
configuration-path: .github/labeler.yml
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build-and-publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write # required for trusted publishing
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v3
|
|
19
|
+
|
|
20
|
+
- name: Build package
|
|
21
|
+
run: uv build
|
|
22
|
+
|
|
23
|
+
- name: Publish to PyPI
|
|
24
|
+
run: uv publish
|
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
## Linting and formatting
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv run ruff check .
|
|
42
|
+
uv run ruff format .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Both must pass before opening a PR. CI enforces this.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Adding a new template
|
|
50
|
+
|
|
51
|
+
Templates follow a consistent three-file pattern. MCP Server (`src/spawn/templates/mcp_server/`) is the cleanest minimal example to copy from.
|
|
52
|
+
|
|
53
|
+
### 1. Create the template package
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
src/spawn/templates/<your_slug>/
|
|
57
|
+
__init__.py # MyTemplate(BaseTemplate) class
|
|
58
|
+
content.py # string constants + make_readme() + make_agents_md()
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**`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.
|
|
62
|
+
|
|
63
|
+
**`__init__.py`** subclasses `BaseTemplate`:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
class MyTemplate(BaseTemplate):
|
|
67
|
+
def __init__(self, extras: list[str] | None = None) -> None:
|
|
68
|
+
self.extras = extras or []
|
|
69
|
+
super().__init__(
|
|
70
|
+
name="My Template",
|
|
71
|
+
folders=["src", "tests"],
|
|
72
|
+
starter_files=[
|
|
73
|
+
("src/__init__.py", INIT_CONTENT),
|
|
74
|
+
("src/main.py", MAIN_CONTENT),
|
|
75
|
+
(".env.example", ENV_CONTENT),
|
|
76
|
+
],
|
|
77
|
+
next_steps=["cd {project_name}", "uv run python -m src.main"],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def get_readme_content(self, context: dict) -> str | None:
|
|
81
|
+
return make_readme().format_map(context)
|
|
82
|
+
|
|
83
|
+
def get_agents_md_content(self, context: dict) -> str | None:
|
|
84
|
+
return make_agents_md().format_map(context)
|
|
85
|
+
|
|
86
|
+
def get_dependencies(self) -> list[str]:
|
|
87
|
+
base = ["some-package"]
|
|
88
|
+
if "pytest" in self.extras:
|
|
89
|
+
base.append("pytest")
|
|
90
|
+
return base
|
|
91
|
+
|
|
92
|
+
def post_install(self, project_path: Path) -> None:
|
|
93
|
+
# Write pyproject.toml sections, CI workflows, etc. as needed.
|
|
94
|
+
pass
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
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.
|
|
98
|
+
|
|
99
|
+
### 2. Register in `src/spawn/core/registry.py`
|
|
100
|
+
|
|
101
|
+
Add an import and a `TemplateMetadata` entry to `TEMPLATES`:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from spawn.templates.my_template import MyTemplate
|
|
105
|
+
|
|
106
|
+
TEMPLATES = {
|
|
107
|
+
# ... existing entries ...
|
|
108
|
+
"my-slug": TemplateMetadata(
|
|
109
|
+
slug="my-slug",
|
|
110
|
+
display_name="My Template",
|
|
111
|
+
description="One-line description shown in spawn doctor output",
|
|
112
|
+
template_class=MyTemplate,
|
|
113
|
+
available_extras=["ruff", "pytest", "github-actions"],
|
|
114
|
+
# available_frameworks, available_providers, available_cli_types,
|
|
115
|
+
# available_data_types — only set the fields your template uses.
|
|
116
|
+
),
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`instantiate_template()` inspects the constructor signature and forwards only the fields the class accepts, so no changes to that function are needed.
|
|
121
|
+
|
|
122
|
+
### 3. Write tests
|
|
123
|
+
|
|
124
|
+
Add two test files mirroring the existing pattern:
|
|
125
|
+
|
|
126
|
+
| File | What to test |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `tests/test_<slug>_template.py` | Template constants, `get_dependencies()`, `get_readme_content()`, `py_compile` on each Python starter file, no unescaped braces |
|
|
129
|
+
| `tests/test_<slug>_generator.py` | `ProjectGenerator().generate()` with mocked uv/git/install, directory structure, README content, `.spawn/meta.json` fields |
|
|
130
|
+
|
|
131
|
+
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")`).
|
|
132
|
+
|
|
133
|
+
Also update `tests/test_registry.py`: increment the `len(slugs) == N` assertion and add `assert "my-slug" in slugs`.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Branch and commit conventions
|
|
138
|
+
|
|
139
|
+
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:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
feat: add <slug> template
|
|
143
|
+
fix: handle edge case in parse_structure
|
|
144
|
+
docs: update CONTRIBUTING.md
|
|
145
|
+
chore: bump version to 1.0.8
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Branch off `main`, use a short descriptive name (`feat/my-template`, `fix/windows-path`, etc.).
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## PR expectations
|
|
153
|
+
|
|
154
|
+
- All existing tests must pass (`uv run pytest`).
|
|
155
|
+
- New templates require both a `_template` and a `_generator` test file.
|
|
156
|
+
- `uv run ruff check .` and `uv run ruff format --check .` must be clean.
|
|
157
|
+
- CI (`.github/workflows/ci.yml`) must be green.
|
|
158
|
+
- Keep PRs focused — one template or fix per PR.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Reporting issues / asking questions
|
|
163
|
+
|
|
164
|
+
GitHub Issues are currently **restricted** on this repo. To reach the maintainer:
|
|
165
|
+
|
|
166
|
+
- Open a [GitHub Discussion](https://github.com/Abhiix0/Spawn/discussions) if Discussions are enabled.
|
|
167
|
+
- Otherwise, leave a comment on an existing PR or tag `@Abhiix0` in your PR description.
|
|
168
|
+
|
|
169
|
+
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,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Abhiix0
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abhiix0
|
|
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.
|