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.
Files changed (119) hide show
  1. spawnio-1.0.8/.coderabbit.yaml +105 -0
  2. spawnio-1.0.8/.github/ISSUE_TEMPLATE/bug_report.yml +77 -0
  3. spawnio-1.0.8/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. spawnio-1.0.8/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
  5. spawnio-1.0.8/.github/PULL_REQUEST_TEMPLATE.md +24 -0
  6. spawnio-1.0.8/.github/labeler.yml +25 -0
  7. {spawnio-1.0.6 → spawnio-1.0.8}/.github/workflows/ci.yml +29 -29
  8. spawnio-1.0.8/.github/workflows/pr-check.yml +60 -0
  9. spawnio-1.0.8/.github/workflows/publish.yml +24 -0
  10. spawnio-1.0.8/CONTRIBUTING.md +169 -0
  11. {spawnio-1.0.6 → spawnio-1.0.8}/LICENSE +21 -21
  12. {spawnio-1.0.6 → spawnio-1.0.8}/PKG-INFO +87 -29
  13. {spawnio-1.0.6 → spawnio-1.0.8}/README.md +887 -829
  14. {spawnio-1.0.6 → spawnio-1.0.8}/docs/architecture.md +199 -194
  15. {spawnio-1.0.6 → spawnio-1.0.8}/docs/changelog.md +438 -405
  16. spawnio-1.0.8/docs/commands.md +530 -0
  17. spawnio-1.0.8/docs/getting-started.md +288 -0
  18. {spawnio-1.0.6 → spawnio-1.0.8}/pyproject.toml +29 -28
  19. spawnio-1.0.8/src/spawn/__init__.py +6 -0
  20. spawnio-1.0.8/src/spawn/cli/app.py +374 -0
  21. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/cli/noninteractive.py +217 -204
  22. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/cli/prompts.py +275 -267
  23. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/exceptions.py +8 -7
  24. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/models.py +22 -21
  25. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/registry.py +221 -152
  26. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/generators/custom_structure.py +506 -508
  27. spawnio-1.0.8/src/spawn/generators/project_files.py +191 -0
  28. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/generators/project_generator.py +131 -115
  29. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/exceptions.py +5 -5
  30. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/publisher.py +59 -69
  31. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/validators.py +20 -23
  32. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/agent/__init__.py +184 -182
  33. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/agent/content.py +375 -374
  34. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/automation/__init__.py +95 -100
  35. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/automation/content.py +181 -181
  36. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/backend_api/__init__.py +241 -243
  37. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/backend_api/content.py +509 -509
  38. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/base.py +58 -58
  39. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/chatbot/__init__.py +254 -243
  40. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/chatbot/content.py +658 -668
  41. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/cli_application/__init__.py +218 -211
  42. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/cli_application/content.py +512 -512
  43. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/__init__.py +118 -125
  44. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/analysis/__init__.py +75 -74
  45. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/analysis/content.py +191 -190
  46. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/dashboard/__init__.py +62 -61
  47. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/dashboard/content.py +136 -135
  48. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/etl/__init__.py +67 -66
  49. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/etl/content.py +240 -239
  50. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/ml/__init__.py +63 -62
  51. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/data_project/ml/content.py +240 -239
  52. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/mcp_server/__init__.py +83 -83
  53. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/mcp_server/content.py +161 -161
  54. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/rag/__init__.py +124 -124
  55. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/rag/content.py +464 -463
  56. spawnio-1.0.8/src/spawn/templates/shared_content.py +184 -0
  57. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/banner.py +41 -41
  58. spawnio-1.0.8/src/spawn/utils/console.py +9 -0
  59. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/doctor.py +598 -594
  60. spawnio-1.0.8/src/spawn/utils/doctor_fix.py +226 -0
  61. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/git.py +144 -132
  62. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/success.py +46 -47
  63. spawnio-1.0.8/src/spawn/utils/theme.py +25 -0
  64. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/utils/uv.py +55 -61
  65. spawnio-1.0.8/src/spawn/utils/validators.py +30 -0
  66. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_agent_generator.py +239 -233
  67. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_agent_template.py +241 -233
  68. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_app.py +618 -471
  69. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_automation_generator.py +245 -242
  70. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_automation_template.py +68 -68
  71. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_chatbot_generator.py +333 -312
  72. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_chatbot_template.py +681 -650
  73. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_cli_application_generator.py +297 -224
  74. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_cli_application_template.py +197 -190
  75. spawnio-1.0.8/tests/test_console.py +33 -0
  76. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_custom_structure.py +897 -823
  77. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_custom_structure_integration.py +155 -136
  78. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_analysis.py +189 -187
  79. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_dashboard.py +178 -176
  80. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_etl.py +226 -224
  81. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_gitignore.py +179 -171
  82. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_data_project_ml.py +210 -208
  83. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_doctor.py +710 -679
  84. spawnio-1.0.8/tests/test_doctor_fix.py +223 -0
  85. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_generator.py +871 -710
  86. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_git.py +188 -187
  87. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_github_publisher.py +135 -149
  88. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_github_validators.py +47 -57
  89. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_mcp_server_generator.py +138 -134
  90. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_mcp_server_template.py +157 -157
  91. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_models.py +70 -70
  92. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_noninteractive.py +258 -211
  93. spawnio-1.0.8/tests/test_project_files.py +371 -0
  94. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_prompts.py +499 -406
  95. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_rag_generator.py +237 -230
  96. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_rag_template.py +339 -324
  97. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_registry.py +244 -186
  98. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_templates.py +262 -252
  99. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_uv.py +87 -89
  100. {spawnio-1.0.6 → spawnio-1.0.8}/tests/test_validators.py +123 -93
  101. spawnio-1.0.8/uv.lock +333 -0
  102. spawnio-1.0.6/docs/commands.md +0 -514
  103. spawnio-1.0.6/docs/getting-started.md +0 -204
  104. spawnio-1.0.6/src/spawn/__init__.py +0 -6
  105. spawnio-1.0.6/src/spawn/cli/app.py +0 -217
  106. spawnio-1.0.6/src/spawn/templates/shared_content.py +0 -89
  107. spawnio-1.0.6/src/spawn/utils/console.py +0 -3
  108. spawnio-1.0.6/src/spawn/utils/theme.py +0 -25
  109. spawnio-1.0.6/src/spawn/utils/validators.py +0 -15
  110. spawnio-1.0.6/uv.lock +0 -218
  111. {spawnio-1.0.6 → spawnio-1.0.8}/.gitignore +0 -0
  112. {spawnio-1.0.6 → spawnio-1.0.8}/.python-version +0 -0
  113. {spawnio-1.0.6 → spawnio-1.0.8}/assets/preview.png +0 -0
  114. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/cli/__init__.py +0 -0
  115. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/core/__init__.py +0 -0
  116. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/generators/__init__.py +0 -0
  117. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/github/__init__.py +0 -0
  118. {spawnio-1.0.6 → spawnio-1.0.8}/src/spawn/templates/__init__.py +0 -0
  119. {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,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: GitHub Discussions
4
+ url: https://github.com/Abhiix0/Spawn/discussions
5
+ about: Ask questions, share ideas, or discuss spawnio without filing a formal issue.
@@ -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.