amctl 0.1.0__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.
amctl-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AmritaConstant
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.
amctl-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,270 @@
1
+ Metadata-Version: 2.4
2
+ Name: amctl
3
+ Version: 0.1.0
4
+ Summary: CLI for Project Amrita
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: click>=8.4.1
10
+ Requires-Dist: colorama>=0.4.6
11
+ Requires-Dist: importlib>=1.0.4
12
+ Requires-Dist: jinja2>=3.1.6
13
+ Requires-Dist: requests>=2.34.2
14
+ Requires-Dist: tomli>=2.4.1
15
+ Requires-Dist: uv>=0.11.17
16
+ Dynamic: license-file
17
+
18
+ # Amctl
19
+
20
+ **CLI for Project Amrita** — scaffold, manage, and maintain Python projects
21
+ with the Amrita ecosystem.
22
+
23
+ [![Python](https://img.shields.io/badge/python-%3E%3D3.10-blue)](https://pypi.org/project/amctl/)
24
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ # From PyPI
32
+ uv tool install amctl
33
+
34
+ # By uv
35
+ uv tool install amctl
36
+
37
+ # From GitHub
38
+ uv tool install git+https://github.com/AmritaBot/Amctl.git
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```bash
44
+ # List available templates
45
+ amctl list
46
+
47
+ # Create a new project
48
+ amctl create -t amrita_core -n myapp
49
+ cd myapp
50
+ uv sync
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Commands
56
+
57
+ ### `amctl create`
58
+
59
+ Scaffold a new project from a template.
60
+
61
+ ```bash
62
+ amctl create -t amrita_core -n myapp
63
+ amctl create -t amrita_core -n myapp --description="My awesome project"
64
+ amctl create -t amrita_core -n myapp -V 0.8.0 -o /tmp
65
+
66
+ # Bypass Python version resolution
67
+ amctl create -t amrita_core -n myapp --frozen
68
+
69
+ # Force a specific version not in the known list
70
+ amctl create -t amrita_core -n myapp --force-version 3.0-beta
71
+ ```
72
+
73
+ | Option | Description |
74
+ | ----------------- | --------------------------------------------------- |
75
+ | `-t`, `--type` | Template type (e.g. `amrita_core`) |
76
+ | `-n`, `--name` | Project name |
77
+ | `-V`, `--version` | Template version (default: latest) |
78
+ | `-o`, `--output` | Output directory (default: `.`) |
79
+ | `-f`, `--force` | Overwrite existing directory |
80
+ | `--force-version` | Use any version string, bypassing validation |
81
+ | `--frozen` | Skip Python version selection and `.python-version` |
82
+
83
+ Template-specific fields (declared via `__tmpl_fields__`) are passed as
84
+ dynamic CLI flags:
85
+
86
+ ```bash
87
+ amctl create -t amrita_core -n myapp --description="Hello" --port=8080
88
+ ```
89
+
90
+ After scaffolding, you are prompted to choose a license interactively:
91
+
92
+ ```
93
+ [?] Choose a license for your project:
94
+ [1] MIT
95
+ [2] Apache-2.0
96
+ [3] GPL-3.0
97
+ [4] None (skip)
98
+ License [4]: _
99
+ ```
100
+
101
+ A `LICENSE` file is written to the project root when a known license is
102
+ selected.
103
+
104
+ ---
105
+
106
+ ### `amctl list`
107
+
108
+ List all registered templates.
109
+
110
+ ```bash
111
+ amctl list # compact (first 5 versions shown)
112
+ amctl list -v # verbose — full version lists
113
+ ```
114
+
115
+ ---
116
+
117
+ ### `amctl info`
118
+
119
+ Show detailed information about a template.
120
+
121
+ ```bash
122
+ amctl info amrita_core
123
+ ```
124
+
125
+ Output includes description, available versions (with source labels),
126
+ declared fields (name/type/default/required/description), and the expected
127
+ template file tree.
128
+
129
+ ---
130
+
131
+ ### `amctl fix`
132
+
133
+ Check for missing template files and restore them.
134
+
135
+ ```bash
136
+ amctl fix --check # dry-run — report missing files only
137
+ amctl fix # interactive [Y/N/M] confirmation
138
+ amctl fix --force # restore all missing files without prompting
139
+ amctl fix --exclude '["README.md",".gitignore"]' # skip specific files
140
+ ```
141
+
142
+ | Option | Description |
143
+ | --------------- | ------------------------------------- |
144
+ | `--check` | Dry-run — show what would be restored |
145
+ | `--force`, `-f` | Skip confirmation, restore everything |
146
+ | `--exclude` | JSON array or single path to exclude |
147
+
148
+ ---
149
+
150
+ ### `amctl man`
151
+
152
+ Run project scripts defined in `pyproject.toml` under
153
+ `[tools.amctl.scripts]`.
154
+
155
+ ```toml
156
+ # pyproject.toml
157
+ [tools.amctl.scripts]
158
+ lint = "uv run ruff check ."
159
+ test = "uv run pytest -v"
160
+ start = "uv run uvicorn myapp.main:app --reload"
161
+ ```
162
+
163
+ ```bash
164
+ amctl man lint
165
+ amctl man test -- --cov
166
+ amctl man start
167
+ ```
168
+
169
+ Extra arguments after `--` are forwarded to the script.
170
+
171
+ ---
172
+
173
+ ### `amctl tmpl`
174
+
175
+ Template-specific sub-commands. Each registered template is a sub-group.
176
+
177
+ ```bash
178
+ amctl tmpl amrita_core # show field summary (if no commands registered)
179
+ ```
180
+
181
+ Templates can register custom commands via `get_tmpl_commands()`.
182
+
183
+ ---
184
+
185
+ ### `amctl self`
186
+
187
+ Manage amctl itself.
188
+
189
+ ```bash
190
+ amctl self cache show # display version cache contents
191
+ amctl self cache fresh # refresh cache from PyPI
192
+ amctl self cache clean # delete the cache file
193
+ amctl self tmpl-upd # check for template package updates
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Version Resolution
199
+
200
+ Amctl resolves available template versions through a **cache-first
201
+ fallback chain**:
202
+
203
+ ```
204
+ fresh cache (24h TTL) → PyPI → expired cache (warn) → hardcoded fallback
205
+ ```
206
+
207
+ **Cache location** (in priority order):
208
+
209
+ 1. `$AMCTL_TMPL_CACHEPATH` — explicit path
210
+ 2. `.venv/.amctl/versions_cache.json` — inside a virtualenv project
211
+ 3. `~/.amctl/versions_cache.json` — global
212
+
213
+ **Environment variables**:
214
+
215
+ | Variable | Description |
216
+ | --------------------------- | -------------------------------------------- |
217
+ | `AMCTL_TMPL_CACHEPATH` | Custom cache directory |
218
+ | `AMCTL_TMPL_USECACHE=false` | Disable local cache (still uses PyPI) |
219
+ | `AMCTL_TMPL_NOPYPI=true` | Block all PyPI requests (air-gapped) |
220
+ | `AMCTL_LOG_LEVEL=debug` | Enable debug logging for network diagnostics |
221
+
222
+ Each version carries a `requires_python` constraint obtained from PyPI.
223
+ Amctl attempts to resolve a compatible Python interpreter using `uv
224
+ python list` and writes a `.python-version` file to the project root.
225
+
226
+ ---
227
+
228
+ ## Creating a Template
229
+
230
+ Templates are auto-discovered from `src/amctl/templ/<name>/`. Define a
231
+ class with the required dunder attributes:
232
+
233
+ ```python
234
+ from amctl.templating import BaseTemplate, field
235
+
236
+ class MyTemplate(BaseTemplate):
237
+ __template_name__ = "my_template"
238
+ __template_description__ = "A custom project template"
239
+ __core_package__ = "my-core-lib" # PyPI package for version discovery
240
+ __python_requires__ = ">=3.11" # Python version constraint
241
+ __versions__ = ("1.0",) # hardcoded fallback
242
+ __tmpl_fields__ = {
243
+ "description": field(default="desc"),
244
+ "port": field(default=8000, type=int, required=True),
245
+ }
246
+
247
+ def on_create(self, project_dir, name, version=None, **fields):
248
+ super().on_create(project_dir, name, version=version, **fields)
249
+
250
+ __template_export__ = MyTemplate
251
+ ```
252
+
253
+ Template files go in the same directory and use the `.tmpl` extension
254
+ for Jinja2 rendering. Directory names containing `{{ }}` markers are
255
+ also rendered (e.g. `src/{{ name }}/__init__.py.tmpl`).
256
+
257
+ ---
258
+
259
+ ## Development
260
+
261
+ ```bash
262
+ uv sync
263
+ uv run ruff check src/ # lint
264
+ uv run pyright src/ # type-check
265
+ uv run amctl --help
266
+ ```
267
+
268
+ ## License
269
+
270
+ MIT — see [LICENSE](LICENSE).
amctl-0.1.0/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # Amctl
2
+
3
+ **CLI for Project Amrita** — scaffold, manage, and maintain Python projects
4
+ with the Amrita ecosystem.
5
+
6
+ [![Python](https://img.shields.io/badge/python-%3E%3D3.10-blue)](https://pypi.org/project/amctl/)
7
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
8
+
9
+ ---
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # From PyPI
15
+ uv tool install amctl
16
+
17
+ # By uv
18
+ uv tool install amctl
19
+
20
+ # From GitHub
21
+ uv tool install git+https://github.com/AmritaBot/Amctl.git
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```bash
27
+ # List available templates
28
+ amctl list
29
+
30
+ # Create a new project
31
+ amctl create -t amrita_core -n myapp
32
+ cd myapp
33
+ uv sync
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Commands
39
+
40
+ ### `amctl create`
41
+
42
+ Scaffold a new project from a template.
43
+
44
+ ```bash
45
+ amctl create -t amrita_core -n myapp
46
+ amctl create -t amrita_core -n myapp --description="My awesome project"
47
+ amctl create -t amrita_core -n myapp -V 0.8.0 -o /tmp
48
+
49
+ # Bypass Python version resolution
50
+ amctl create -t amrita_core -n myapp --frozen
51
+
52
+ # Force a specific version not in the known list
53
+ amctl create -t amrita_core -n myapp --force-version 3.0-beta
54
+ ```
55
+
56
+ | Option | Description |
57
+ | ----------------- | --------------------------------------------------- |
58
+ | `-t`, `--type` | Template type (e.g. `amrita_core`) |
59
+ | `-n`, `--name` | Project name |
60
+ | `-V`, `--version` | Template version (default: latest) |
61
+ | `-o`, `--output` | Output directory (default: `.`) |
62
+ | `-f`, `--force` | Overwrite existing directory |
63
+ | `--force-version` | Use any version string, bypassing validation |
64
+ | `--frozen` | Skip Python version selection and `.python-version` |
65
+
66
+ Template-specific fields (declared via `__tmpl_fields__`) are passed as
67
+ dynamic CLI flags:
68
+
69
+ ```bash
70
+ amctl create -t amrita_core -n myapp --description="Hello" --port=8080
71
+ ```
72
+
73
+ After scaffolding, you are prompted to choose a license interactively:
74
+
75
+ ```
76
+ [?] Choose a license for your project:
77
+ [1] MIT
78
+ [2] Apache-2.0
79
+ [3] GPL-3.0
80
+ [4] None (skip)
81
+ License [4]: _
82
+ ```
83
+
84
+ A `LICENSE` file is written to the project root when a known license is
85
+ selected.
86
+
87
+ ---
88
+
89
+ ### `amctl list`
90
+
91
+ List all registered templates.
92
+
93
+ ```bash
94
+ amctl list # compact (first 5 versions shown)
95
+ amctl list -v # verbose — full version lists
96
+ ```
97
+
98
+ ---
99
+
100
+ ### `amctl info`
101
+
102
+ Show detailed information about a template.
103
+
104
+ ```bash
105
+ amctl info amrita_core
106
+ ```
107
+
108
+ Output includes description, available versions (with source labels),
109
+ declared fields (name/type/default/required/description), and the expected
110
+ template file tree.
111
+
112
+ ---
113
+
114
+ ### `amctl fix`
115
+
116
+ Check for missing template files and restore them.
117
+
118
+ ```bash
119
+ amctl fix --check # dry-run — report missing files only
120
+ amctl fix # interactive [Y/N/M] confirmation
121
+ amctl fix --force # restore all missing files without prompting
122
+ amctl fix --exclude '["README.md",".gitignore"]' # skip specific files
123
+ ```
124
+
125
+ | Option | Description |
126
+ | --------------- | ------------------------------------- |
127
+ | `--check` | Dry-run — show what would be restored |
128
+ | `--force`, `-f` | Skip confirmation, restore everything |
129
+ | `--exclude` | JSON array or single path to exclude |
130
+
131
+ ---
132
+
133
+ ### `amctl man`
134
+
135
+ Run project scripts defined in `pyproject.toml` under
136
+ `[tools.amctl.scripts]`.
137
+
138
+ ```toml
139
+ # pyproject.toml
140
+ [tools.amctl.scripts]
141
+ lint = "uv run ruff check ."
142
+ test = "uv run pytest -v"
143
+ start = "uv run uvicorn myapp.main:app --reload"
144
+ ```
145
+
146
+ ```bash
147
+ amctl man lint
148
+ amctl man test -- --cov
149
+ amctl man start
150
+ ```
151
+
152
+ Extra arguments after `--` are forwarded to the script.
153
+
154
+ ---
155
+
156
+ ### `amctl tmpl`
157
+
158
+ Template-specific sub-commands. Each registered template is a sub-group.
159
+
160
+ ```bash
161
+ amctl tmpl amrita_core # show field summary (if no commands registered)
162
+ ```
163
+
164
+ Templates can register custom commands via `get_tmpl_commands()`.
165
+
166
+ ---
167
+
168
+ ### `amctl self`
169
+
170
+ Manage amctl itself.
171
+
172
+ ```bash
173
+ amctl self cache show # display version cache contents
174
+ amctl self cache fresh # refresh cache from PyPI
175
+ amctl self cache clean # delete the cache file
176
+ amctl self tmpl-upd # check for template package updates
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Version Resolution
182
+
183
+ Amctl resolves available template versions through a **cache-first
184
+ fallback chain**:
185
+
186
+ ```
187
+ fresh cache (24h TTL) → PyPI → expired cache (warn) → hardcoded fallback
188
+ ```
189
+
190
+ **Cache location** (in priority order):
191
+
192
+ 1. `$AMCTL_TMPL_CACHEPATH` — explicit path
193
+ 2. `.venv/.amctl/versions_cache.json` — inside a virtualenv project
194
+ 3. `~/.amctl/versions_cache.json` — global
195
+
196
+ **Environment variables**:
197
+
198
+ | Variable | Description |
199
+ | --------------------------- | -------------------------------------------- |
200
+ | `AMCTL_TMPL_CACHEPATH` | Custom cache directory |
201
+ | `AMCTL_TMPL_USECACHE=false` | Disable local cache (still uses PyPI) |
202
+ | `AMCTL_TMPL_NOPYPI=true` | Block all PyPI requests (air-gapped) |
203
+ | `AMCTL_LOG_LEVEL=debug` | Enable debug logging for network diagnostics |
204
+
205
+ Each version carries a `requires_python` constraint obtained from PyPI.
206
+ Amctl attempts to resolve a compatible Python interpreter using `uv
207
+ python list` and writes a `.python-version` file to the project root.
208
+
209
+ ---
210
+
211
+ ## Creating a Template
212
+
213
+ Templates are auto-discovered from `src/amctl/templ/<name>/`. Define a
214
+ class with the required dunder attributes:
215
+
216
+ ```python
217
+ from amctl.templating import BaseTemplate, field
218
+
219
+ class MyTemplate(BaseTemplate):
220
+ __template_name__ = "my_template"
221
+ __template_description__ = "A custom project template"
222
+ __core_package__ = "my-core-lib" # PyPI package for version discovery
223
+ __python_requires__ = ">=3.11" # Python version constraint
224
+ __versions__ = ("1.0",) # hardcoded fallback
225
+ __tmpl_fields__ = {
226
+ "description": field(default="desc"),
227
+ "port": field(default=8000, type=int, required=True),
228
+ }
229
+
230
+ def on_create(self, project_dir, name, version=None, **fields):
231
+ super().on_create(project_dir, name, version=version, **fields)
232
+
233
+ __template_export__ = MyTemplate
234
+ ```
235
+
236
+ Template files go in the same directory and use the `.tmpl` extension
237
+ for Jinja2 rendering. Directory names containing `{{ }}` markers are
238
+ also rendered (e.g. `src/{{ name }}/__init__.py.tmpl`).
239
+
240
+ ---
241
+
242
+ ## Development
243
+
244
+ ```bash
245
+ uv sync
246
+ uv run ruff check src/ # lint
247
+ uv run pyright src/ # type-check
248
+ uv run amctl --help
249
+ ```
250
+
251
+ ## License
252
+
253
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,70 @@
1
+ [project]
2
+ name = "amctl"
3
+ version = "0.1.0"
4
+ description = "CLI for Project Amrita"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ requires-python = ">=3.10"
8
+ dependencies = [
9
+ "click>=8.4.1",
10
+ "colorama>=0.4.6",
11
+ "importlib>=1.0.4",
12
+ "jinja2>=3.1.6",
13
+ "requests>=2.34.2",
14
+ "tomli>=2.4.1",
15
+ "uv>=0.11.17",
16
+ ]
17
+
18
+ [project.scripts]
19
+ amctl = "amctl:__main__.main"
20
+
21
+ [tool.setuptools.packages.find]
22
+ where = ["src"]
23
+ include = ["amctl","amctl.*"]
24
+
25
+ [tool.setuptools.package-data]
26
+ "amctl" = ["templ/*.tmpl"]
27
+
28
+ [tool.uv]
29
+ dev-dependencies = [
30
+ "ruff>=0.12.8",
31
+ # "pytest>=8.4.1",
32
+ "py-spy>=0.4.1",
33
+ "pyright>=1.1.407",
34
+ ]
35
+ package = true
36
+
37
+ [tool.uv.sources]
38
+ amctl = { workspace = true }
39
+
40
+ [tool.ruff]
41
+ line-length = 88
42
+ target-version = "py310"
43
+
44
+ [tool.ruff.lint]
45
+ select = [
46
+ "F", # Pyflakes
47
+ "W", # pycodestyle warnings
48
+ "E", # pycodestyle errors
49
+ "UP", # pyupgrade
50
+ "ASYNC", # flake8-async
51
+ "C4", # flake8-comprehensions
52
+ "T10", # flake8-debugger
53
+ "PYI", # flake8-pyi
54
+ "PT", # flake8-pytest-style
55
+ "Q", # flake8-quotes
56
+ "RUF", # Ruff-specific rules
57
+ "I", # isort
58
+ "PERF", # pylint-performance
59
+ ]
60
+ ignore = [
61
+ "E402", # module-import-not-at-top-of-file
62
+ "E501", # line-too-long
63
+ "UP037", # quoted-annotation
64
+ "RUF001", # ambiguous-unicode-character-string
65
+ "RUF002", # ambiguous-unicode-character-docstring
66
+ "RUF003", # ambiguous-unicode-character-comment
67
+ ]
68
+
69
+ [tool.pyright]
70
+ typeCheckingMode = "standard"
amctl-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,17 @@
1
+ from . import templ
2
+ from .colors import ColorLog as ColorLog
3
+ from .templating import BaseTemplate as BaseTemplate
4
+ from .templating import TemplateManager as TemplateManager
5
+ from .templating import TmplField as TmplField
6
+ from .templating import field as field
7
+ from .uv_util import UvOperator as UvOperator
8
+
9
+ __all__ = [
10
+ "BaseTemplate",
11
+ "ColorLog",
12
+ "TemplateManager",
13
+ "TmplField",
14
+ "UvOperator",
15
+ "field",
16
+ "templ",
17
+ ]
@@ -0,0 +1,9 @@
1
+ from .cli import cli
2
+
3
+
4
+ def main() -> None:
5
+ cli()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,15 @@
1
+ """What is this?"""
2
+
3
+ f = """\
4
+ Vg qbrf abg pbasbez gb svkrq sbezf. Vg oraqf. Vg sybjf. Vg nqncgf.
5
+ Yvxr jngre, vg svyyf rirel fcnpr vg arrqf, ab evtvqvgl, ab haarprffnel jrvtug, ab sbeprq obhaqnevrf.
6
+ Vg zbirf jvgu gur ybtvp bs vagryyvtrapr, abg gur yvzvgf bs fgehpgher.
7
+ Guvf vf gur fcvevg bs Nzevgn."""
8
+
9
+
10
+ def _get_bug() -> str:
11
+ d: dict[str, str] = {}
12
+ for c in (65, 97): # Just a ROT13, right?
13
+ for i in range(26):
14
+ d[chr(i + c)] = chr((i + 13) % 26 + c)
15
+ return "".join(d.get(c, c) for c in f)