macrostates-cli 0.3.1__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.
- macrostates_cli-0.3.1/.macrostates/implementation/release.yaml +3 -0
- macrostates_cli-0.3.1/LICENSE +21 -0
- macrostates_cli-0.3.1/MANIFEST.in +1 -0
- macrostates_cli-0.3.1/PKG-INFO +259 -0
- macrostates_cli-0.3.1/README.md +244 -0
- macrostates_cli-0.3.1/pyproject.toml +60 -0
- macrostates_cli-0.3.1/setup.cfg +4 -0
- macrostates_cli-0.3.1/src/macrostates/__init__.py +23 -0
- macrostates_cli-0.3.1/src/macrostates/__main__.py +4 -0
- macrostates_cli-0.3.1/src/macrostates/_build_version.py +56 -0
- macrostates_cli-0.3.1/src/macrostates/_cli.py +158 -0
- macrostates_cli-0.3.1/src/macrostates/_formats/__init__.py +42 -0
- macrostates_cli-0.3.1/src/macrostates/_formats/common.py +102 -0
- macrostates_cli-0.3.1/src/macrostates/_formats/v0.py +11 -0
- macrostates_cli-0.3.1/src/macrostates/_formats/v1.py +44 -0
- macrostates_cli-0.3.1/src/macrostates/_integrity.py +144 -0
- macrostates_cli-0.3.1/src/macrostates/_io.py +118 -0
- macrostates_cli-0.3.1/src/macrostates/_models.py +71 -0
- macrostates_cli-0.3.1/src/macrostates/_mutations.py +53 -0
- macrostates_cli-0.3.1/src/macrostates/_project.py +527 -0
- macrostates_cli-0.3.1/src/macrostates/_scopes.py +34 -0
- macrostates_cli-0.3.1/src/macrostates/_sources.py +153 -0
- macrostates_cli-0.3.1/src/macrostates/_staged.py +56 -0
- macrostates_cli-0.3.1/src/macrostates/_validation.py +274 -0
- macrostates_cli-0.3.1/src/macrostates/py.typed +0 -0
- macrostates_cli-0.3.1/src/macrostates_cli.egg-info/PKG-INFO +259 -0
- macrostates_cli-0.3.1/src/macrostates_cli.egg-info/SOURCES.txt +29 -0
- macrostates_cli-0.3.1/src/macrostates_cli.egg-info/dependency_links.txt +1 -0
- macrostates_cli-0.3.1/src/macrostates_cli.egg-info/entry_points.txt +2 -0
- macrostates_cli-0.3.1/src/macrostates_cli.egg-info/requires.txt +1 -0
- macrostates_cli-0.3.1/src/macrostates_cli.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lucas Lopez
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include .macrostates/implementation/release.yaml
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: macrostates-cli
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Compose, install and validate versioned Macrostates specification packages.
|
|
5
|
+
Author-email: Lucas Lopez <713375+lucaslopez@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/Macrostates/macrostates-cli
|
|
8
|
+
Project-URL: Documentation, https://github.com/Macrostates/macrostates-cli#readme
|
|
9
|
+
Project-URL: Issues, https://github.com/Macrostates/macrostates-cli/issues
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: PyYAML<7,>=6.0.2
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# Macrostates CLI
|
|
17
|
+
|
|
18
|
+
Install, inspect and check reusable specification packages. Packages stay in
|
|
19
|
+
numbered, version-controlled directories such as `000_meta/` and `001_process/`.
|
|
20
|
+
The `macrostates` command and the `macrostates` Python API share the same core.
|
|
21
|
+
|
|
22
|
+
Requires Python 3.12 or newer. Distribution name: `macrostates-cli`.
|
|
23
|
+
Import package and executable name: `macrostates`. Version 0.3.1 is an initial
|
|
24
|
+
API; compatibility changes will be documented. Licensed under [MIT](https://github.com/Macrostates/macrostates-cli/blob/main/LICENSE).
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Install from [PyPI](https://pypi.org/project/macrostates-cli/) with pip in a
|
|
29
|
+
Python 3.12 or newer environment:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python -m pip install macrostates-cli
|
|
33
|
+
macrostates --help
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Use `python -m pip install macrostates-cli==0.3.1` for a fixed version, or
|
|
37
|
+
`python -m pip install --upgrade macrostates-cli` to update it. If your Python
|
|
38
|
+
installation requires a virtual environment, create one with
|
|
39
|
+
`python -m venv .venv` and activate it before installing.
|
|
40
|
+
|
|
41
|
+
For a command available outside a project environment, use
|
|
42
|
+
`pipx install macrostates-cli` or `uv tool install macrostates-cli`. Contributors
|
|
43
|
+
can clone the repository and run `uv sync --locked` as described below.
|
|
44
|
+
|
|
45
|
+
## Start a project
|
|
46
|
+
|
|
47
|
+
Supply a composition whose package versions, authority and reading orders you
|
|
48
|
+
have selected. [The minimal composition](https://github.com/Macrostates/macrostates-cli/blob/main/examples/composition.yaml) selects only
|
|
49
|
+
Meta; add Process and the technology packages appropriate to your project.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
macrostates init --from /path/to/composition.yaml
|
|
53
|
+
macrostates install
|
|
54
|
+
macrostates info
|
|
55
|
+
macrostates check
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For a short setup, `macrostates init --name my-project --package meta@2.1.0`
|
|
59
|
+
creates a composition. Repeat `--package NAME@VERSION` for additional packages.
|
|
60
|
+
This shorthand uses the order you supplied for both reading and authority
|
|
61
|
+
(highest first); review those orders before installation. It does not select
|
|
62
|
+
dependencies automatically or replace versions with the latest releases.
|
|
63
|
+
Use `--from` for custom sources or deliberate orders.
|
|
64
|
+
|
|
65
|
+
The default layout is:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
AGENTS.md
|
|
69
|
+
.macrostates/
|
|
70
|
+
specs/
|
|
71
|
+
main.md
|
|
72
|
+
composition.yaml
|
|
73
|
+
composition.lock.yaml
|
|
74
|
+
000_meta/
|
|
75
|
+
...
|
|
76
|
+
implementation/
|
|
77
|
+
main.md
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Commit the manifest, lockfile, package directories and project specifications.
|
|
81
|
+
Initialization preserves existing agent instructions and refuses to overwrite
|
|
82
|
+
project files. It prepares specification files; it does not implement an app.
|
|
83
|
+
Meta 2.0/2.1 and Process 3.0/4.0/4.1 define this layout. Their numbered packages and locks
|
|
84
|
+
remain tracked in Git. The CLI is strongly recommended and optional; reading
|
|
85
|
+
specifications and manual checks remain necessary for requirements beyond its
|
|
86
|
+
coverage. Existing projects keep their selected policies until explicitly migrated.
|
|
87
|
+
|
|
88
|
+
## Commands
|
|
89
|
+
|
|
90
|
+
| Command | Purpose | Network / writes |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| `init` | Prepare selected specification files | Local writes |
|
|
93
|
+
| `install` | Download and validate selected archive releases | Network and package/lock writes |
|
|
94
|
+
| `install --locked` | Restore an unchanged, locked selection | Network and package/lock writes |
|
|
95
|
+
| `lock` | Compare existing copies with canonical releases, then record integrity | Network and lock write |
|
|
96
|
+
| `verify` | Detect modified, missing or additional package files and executable changes | Offline, read-only |
|
|
97
|
+
| `lint` | Check metadata, dependencies, cycles, entrypoints, orders and local links | Offline, read-only |
|
|
98
|
+
| `info` | Display packages, provenance and dependency/order information | Offline, read-only |
|
|
99
|
+
| `check` | Combine lint and verify | Offline, read-only |
|
|
100
|
+
| `check --staged` | Check the Git index, including partially staged edits | Offline, read-only |
|
|
101
|
+
|
|
102
|
+
All commands accept `--project PATH` and `--json` before or after the command.
|
|
103
|
+
Project discovery selects the nearest composition and stops at the Git root.
|
|
104
|
+
It rejects competing `.yaml`/`.yml` manifests and ambiguous legacy/modern layouts.
|
|
105
|
+
Exit codes: **0** success, **1** failed checks, **2** invalid input/operation.
|
|
106
|
+
Argparse usage errors use its standard text output and exit code 2.
|
|
107
|
+
|
|
108
|
+
Local packages use `source: {type: local}` and are freely editable. Their metadata
|
|
109
|
+
and links are linted; they are excluded from downloaded-package integrity checks.
|
|
110
|
+
Every external package needs a real source to establish a lock. `lock` never
|
|
111
|
+
accepts local modifications as the baseline: it compares against the release.
|
|
112
|
+
|
|
113
|
+
### Updating and recovering
|
|
114
|
+
|
|
115
|
+
Updates are deliberate manifest edits: change the
|
|
116
|
+
selected `version` and `source.tag` together, update the human entrypoint, then
|
|
117
|
+
run `install`. It replaces an old package only if its files still match its
|
|
118
|
+
previous locked inventory. Modified packages are left intact. A missing package
|
|
119
|
+
directory can be restored with `install --locked`.
|
|
120
|
+
|
|
121
|
+
Locks record full commit IDs and SHA-256 hashes of extracted file contents and
|
|
122
|
+
executable flags. ZIP/tar compression is not part of identity. Reinstallation
|
|
123
|
+
checks that the tag still selects its locked commit and fails if the tag moved.
|
|
124
|
+
The lock is a reviewable integrity baseline, not a digital signature: review its
|
|
125
|
+
changes together with package changes. `verify` is offline and cannot determine
|
|
126
|
+
whether a tag moved remotely.
|
|
127
|
+
|
|
128
|
+
Package operations validate all downloads and dependencies before replacing
|
|
129
|
+
files and roll back ordinary filesystem failures. A simultaneous CLI operation
|
|
130
|
+
is refused. An unexpected process termination may leave `.macrostates-operation`
|
|
131
|
+
and a `.macrostates-install-*` recovery directory; inspect those before removing
|
|
132
|
+
the marker or attempting recovery. Power-loss/crash-atomic filesystem commits
|
|
133
|
+
are not promised.
|
|
134
|
+
|
|
135
|
+
### Private packages
|
|
136
|
+
|
|
137
|
+
The downloader accepts credential-free GitHub HTTPS or SSH repository URLs.
|
|
138
|
+
It uses an explicit Python API token, then `GH_TOKEN`/`GITHUB_TOKEN`, then an
|
|
139
|
+
existing GitHub CLI login. Tokens are never stored in composition or lockfiles.
|
|
140
|
+
Initialization and offline commands do not look up credentials. Package imports
|
|
141
|
+
do not execute downloaded code.
|
|
142
|
+
|
|
143
|
+
### Checks before commits
|
|
144
|
+
|
|
145
|
+
Add the following entry to an existing pre-commit configuration after arranging
|
|
146
|
+
installation of the selected CLI version:
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
repos:
|
|
150
|
+
- repo: local
|
|
151
|
+
hooks:
|
|
152
|
+
- id: macrostates
|
|
153
|
+
name: Check staged Macrostates specifications
|
|
154
|
+
entry: macrostates check --staged
|
|
155
|
+
language: system
|
|
156
|
+
pass_filenames: false
|
|
157
|
+
always_run: true
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Run `macrostates check` in CI too. The CLI does not install hooks or change Git
|
|
161
|
+
settings automatically. Staged snapshots currently have a 128 MiB size limit
|
|
162
|
+
and exclude submodule contents. Structural checks do not prove semantic
|
|
163
|
+
consistency or implementation conformance. The local Markdown link checker
|
|
164
|
+
checks file targets, skips fenced code, and does not validate heading anchors
|
|
165
|
+
or implement a complete Markdown parser.
|
|
166
|
+
|
|
167
|
+
## Python API
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from macrostates import Project
|
|
171
|
+
|
|
172
|
+
project = Project.open("/path/to/project")
|
|
173
|
+
print(project.info())
|
|
174
|
+
report = project.check()
|
|
175
|
+
for diagnostic in report.diagnostics:
|
|
176
|
+
print(diagnostic.code, diagnostic.message, diagnostic.path)
|
|
177
|
+
assert report.ok
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Supported root exports: `Project`, `Report`, `Diagnostic`, `MacrostatesError`,
|
|
181
|
+
`GitHubSource`, and `SourceProvider`. `Project.open` and `Project.initialize`
|
|
182
|
+
construct projects; `install`, `lock`, `verify`, `lint`, `check`, and `info` are
|
|
183
|
+
the supported operations. `initialize` accepts a composition dictionary/path
|
|
184
|
+
or a `name` plus ordered `(package_name, version)` selections and a `layout`
|
|
185
|
+
of `modern` or `legacy`. Pass `source=GitHubSource(token=...)` for explicit
|
|
186
|
+
authentication or a `SourceProvider` implementation for another test transport.
|
|
187
|
+
`install(locked=True)` requires unchanged locked selections; `check(staged=True)`
|
|
188
|
+
checks the index. Expected configuration/operation errors raise
|
|
189
|
+
`MacrostatesError`; check failures are returned in `Report.diagnostics`.
|
|
190
|
+
Ordinary file read failures can raise `OSError`. Imports perform no project-local
|
|
191
|
+
or network I/O and do not configure logging. Accessing `__version__` explicitly
|
|
192
|
+
reads installed distribution metadata; it does not read a project declaration. The CLI configures standard logging when explicitly invoked.
|
|
193
|
+
|
|
194
|
+
## Compatibility and development
|
|
195
|
+
|
|
196
|
+
Unversioned compositions use the retained legacy reader. New compositions use
|
|
197
|
+
`schema_version: 1`. Both legacy `specs/` and `.macrostates/specs/` layouts are
|
|
198
|
+
recognized. Existing `git-subtree` compositions can be inspected, linted and
|
|
199
|
+
given an upstream-verified integrity lock without changing subtree history.
|
|
200
|
+
Archive `install` refuses subtree sources; use Git subtree maintenance until an
|
|
201
|
+
explicit migration is requested. Old branch-only/commit selectors need explicit
|
|
202
|
+
tag migration and are reported instead of being silently reinterpreted.
|
|
203
|
+
|
|
204
|
+
Package release versions are independent of format versions. Existing package
|
|
205
|
+
metadata is format 1, as is an explicit `schema_version: 1`. Unknown manifest,
|
|
206
|
+
metadata or lock formats fail clearly. Release policy adapters support Meta
|
|
207
|
+
2.0.x/2.1.x and Process 2.3.x/2.4.x/3.0.x/4.0.x/4.1.x. Modern policies require the modern
|
|
208
|
+
layout; Meta 2 also requires composition format 1. Earlier Meta releases and
|
|
209
|
+
Process 1.x/2.0–2.2 retain their existing checks. Future policy releases receive
|
|
210
|
+
explicit unsupported diagnostics rather than guessed requirements. Process 4's
|
|
211
|
+
feature-branch and PR rules require manual workflow review; CLI checks do not
|
|
212
|
+
verify branch discipline or authorize Git operations.
|
|
213
|
+
|
|
214
|
+
`info` lists directory-scoped specifications under visible component directories;
|
|
215
|
+
`lint` checks their local file links. The scope root is the component containing
|
|
216
|
+
`.macrostates/`. Separately composed subprojects are checked independently.
|
|
217
|
+
Tool/cache/build/temporary and hidden implementation directories are excluded
|
|
218
|
+
from this discovery; inspect their applicable scopes manually. Scope authority,
|
|
219
|
+
semantic requirements and workflow conformance always need specification reading.
|
|
220
|
+
See [architecture](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/implementation/main.md) for adapter extension guidance and
|
|
221
|
+
[project specifications](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/specs/main.md) for this repository's working rules.
|
|
222
|
+
The [CLI specification package](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/specs/051_cli/README.md) defines the
|
|
223
|
+
public library, commands, composition, integrity and versioning contracts;
|
|
224
|
+
[conformance evidence](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/implementation/specification-conformance.md)
|
|
225
|
+
maps those requirements to implementation and verification.
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
uv sync --locked
|
|
229
|
+
uv run ruff check .
|
|
230
|
+
uv run ruff format --check .
|
|
231
|
+
uv run pyright
|
|
232
|
+
uv run pytest --cov=macrostates --cov-report=term-missing
|
|
233
|
+
uv build
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The contributor `uv.lock` is committed for repeatable development and CI.
|
|
237
|
+
Builds go to ignored `dist/`; temporary work goes to `tmp/<activity>/`.
|
|
238
|
+
Automated update planning, workflow commands, release publishing and migrations
|
|
239
|
+
are future features.
|
|
240
|
+
|
|
241
|
+
## This repository's specifications and version
|
|
242
|
+
|
|
243
|
+
The CLI manages its own specification composition under `.macrostates/specs/`,
|
|
244
|
+
using Meta 2.1.0, Process 4.1.0, Repository 3.1.0, Python 2.1.0 and Python-library
|
|
245
|
+
1.1.0 as canonical archive snapshots. Its local CLI requirements remain editable.
|
|
246
|
+
`macrostates check` and `check --staged` validate the same files contributors use.
|
|
247
|
+
This is also a real integration test of the supported package installation path.
|
|
248
|
+
|
|
249
|
+
The implementation's single version declaration is
|
|
250
|
+
[release.yaml](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/implementation/release.yaml); the specification baseline
|
|
251
|
+
is `project.version` in the composition. Setuptools reads the declaration during
|
|
252
|
+
isolated builds. The sdist includes that one declaration, while the wheel reports
|
|
253
|
+
its installed distribution version. Builds do not edit declarations, create tags
|
|
254
|
+
or require Git/network access to obtain release metadata. Ordinary dependency
|
|
255
|
+
installation may still require access to package indexes.
|
|
256
|
+
|
|
257
|
+
## AI assistance
|
|
258
|
+
|
|
259
|
+
This project was developed with AI assistance.
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Macrostates CLI
|
|
2
|
+
|
|
3
|
+
Install, inspect and check reusable specification packages. Packages stay in
|
|
4
|
+
numbered, version-controlled directories such as `000_meta/` and `001_process/`.
|
|
5
|
+
The `macrostates` command and the `macrostates` Python API share the same core.
|
|
6
|
+
|
|
7
|
+
Requires Python 3.12 or newer. Distribution name: `macrostates-cli`.
|
|
8
|
+
Import package and executable name: `macrostates`. Version 0.3.1 is an initial
|
|
9
|
+
API; compatibility changes will be documented. Licensed under [MIT](https://github.com/Macrostates/macrostates-cli/blob/main/LICENSE).
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Install from [PyPI](https://pypi.org/project/macrostates-cli/) with pip in a
|
|
14
|
+
Python 3.12 or newer environment:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python -m pip install macrostates-cli
|
|
18
|
+
macrostates --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Use `python -m pip install macrostates-cli==0.3.1` for a fixed version, or
|
|
22
|
+
`python -m pip install --upgrade macrostates-cli` to update it. If your Python
|
|
23
|
+
installation requires a virtual environment, create one with
|
|
24
|
+
`python -m venv .venv` and activate it before installing.
|
|
25
|
+
|
|
26
|
+
For a command available outside a project environment, use
|
|
27
|
+
`pipx install macrostates-cli` or `uv tool install macrostates-cli`. Contributors
|
|
28
|
+
can clone the repository and run `uv sync --locked` as described below.
|
|
29
|
+
|
|
30
|
+
## Start a project
|
|
31
|
+
|
|
32
|
+
Supply a composition whose package versions, authority and reading orders you
|
|
33
|
+
have selected. [The minimal composition](https://github.com/Macrostates/macrostates-cli/blob/main/examples/composition.yaml) selects only
|
|
34
|
+
Meta; add Process and the technology packages appropriate to your project.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
macrostates init --from /path/to/composition.yaml
|
|
38
|
+
macrostates install
|
|
39
|
+
macrostates info
|
|
40
|
+
macrostates check
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For a short setup, `macrostates init --name my-project --package meta@2.1.0`
|
|
44
|
+
creates a composition. Repeat `--package NAME@VERSION` for additional packages.
|
|
45
|
+
This shorthand uses the order you supplied for both reading and authority
|
|
46
|
+
(highest first); review those orders before installation. It does not select
|
|
47
|
+
dependencies automatically or replace versions with the latest releases.
|
|
48
|
+
Use `--from` for custom sources or deliberate orders.
|
|
49
|
+
|
|
50
|
+
The default layout is:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
AGENTS.md
|
|
54
|
+
.macrostates/
|
|
55
|
+
specs/
|
|
56
|
+
main.md
|
|
57
|
+
composition.yaml
|
|
58
|
+
composition.lock.yaml
|
|
59
|
+
000_meta/
|
|
60
|
+
...
|
|
61
|
+
implementation/
|
|
62
|
+
main.md
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Commit the manifest, lockfile, package directories and project specifications.
|
|
66
|
+
Initialization preserves existing agent instructions and refuses to overwrite
|
|
67
|
+
project files. It prepares specification files; it does not implement an app.
|
|
68
|
+
Meta 2.0/2.1 and Process 3.0/4.0/4.1 define this layout. Their numbered packages and locks
|
|
69
|
+
remain tracked in Git. The CLI is strongly recommended and optional; reading
|
|
70
|
+
specifications and manual checks remain necessary for requirements beyond its
|
|
71
|
+
coverage. Existing projects keep their selected policies until explicitly migrated.
|
|
72
|
+
|
|
73
|
+
## Commands
|
|
74
|
+
|
|
75
|
+
| Command | Purpose | Network / writes |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| `init` | Prepare selected specification files | Local writes |
|
|
78
|
+
| `install` | Download and validate selected archive releases | Network and package/lock writes |
|
|
79
|
+
| `install --locked` | Restore an unchanged, locked selection | Network and package/lock writes |
|
|
80
|
+
| `lock` | Compare existing copies with canonical releases, then record integrity | Network and lock write |
|
|
81
|
+
| `verify` | Detect modified, missing or additional package files and executable changes | Offline, read-only |
|
|
82
|
+
| `lint` | Check metadata, dependencies, cycles, entrypoints, orders and local links | Offline, read-only |
|
|
83
|
+
| `info` | Display packages, provenance and dependency/order information | Offline, read-only |
|
|
84
|
+
| `check` | Combine lint and verify | Offline, read-only |
|
|
85
|
+
| `check --staged` | Check the Git index, including partially staged edits | Offline, read-only |
|
|
86
|
+
|
|
87
|
+
All commands accept `--project PATH` and `--json` before or after the command.
|
|
88
|
+
Project discovery selects the nearest composition and stops at the Git root.
|
|
89
|
+
It rejects competing `.yaml`/`.yml` manifests and ambiguous legacy/modern layouts.
|
|
90
|
+
Exit codes: **0** success, **1** failed checks, **2** invalid input/operation.
|
|
91
|
+
Argparse usage errors use its standard text output and exit code 2.
|
|
92
|
+
|
|
93
|
+
Local packages use `source: {type: local}` and are freely editable. Their metadata
|
|
94
|
+
and links are linted; they are excluded from downloaded-package integrity checks.
|
|
95
|
+
Every external package needs a real source to establish a lock. `lock` never
|
|
96
|
+
accepts local modifications as the baseline: it compares against the release.
|
|
97
|
+
|
|
98
|
+
### Updating and recovering
|
|
99
|
+
|
|
100
|
+
Updates are deliberate manifest edits: change the
|
|
101
|
+
selected `version` and `source.tag` together, update the human entrypoint, then
|
|
102
|
+
run `install`. It replaces an old package only if its files still match its
|
|
103
|
+
previous locked inventory. Modified packages are left intact. A missing package
|
|
104
|
+
directory can be restored with `install --locked`.
|
|
105
|
+
|
|
106
|
+
Locks record full commit IDs and SHA-256 hashes of extracted file contents and
|
|
107
|
+
executable flags. ZIP/tar compression is not part of identity. Reinstallation
|
|
108
|
+
checks that the tag still selects its locked commit and fails if the tag moved.
|
|
109
|
+
The lock is a reviewable integrity baseline, not a digital signature: review its
|
|
110
|
+
changes together with package changes. `verify` is offline and cannot determine
|
|
111
|
+
whether a tag moved remotely.
|
|
112
|
+
|
|
113
|
+
Package operations validate all downloads and dependencies before replacing
|
|
114
|
+
files and roll back ordinary filesystem failures. A simultaneous CLI operation
|
|
115
|
+
is refused. An unexpected process termination may leave `.macrostates-operation`
|
|
116
|
+
and a `.macrostates-install-*` recovery directory; inspect those before removing
|
|
117
|
+
the marker or attempting recovery. Power-loss/crash-atomic filesystem commits
|
|
118
|
+
are not promised.
|
|
119
|
+
|
|
120
|
+
### Private packages
|
|
121
|
+
|
|
122
|
+
The downloader accepts credential-free GitHub HTTPS or SSH repository URLs.
|
|
123
|
+
It uses an explicit Python API token, then `GH_TOKEN`/`GITHUB_TOKEN`, then an
|
|
124
|
+
existing GitHub CLI login. Tokens are never stored in composition or lockfiles.
|
|
125
|
+
Initialization and offline commands do not look up credentials. Package imports
|
|
126
|
+
do not execute downloaded code.
|
|
127
|
+
|
|
128
|
+
### Checks before commits
|
|
129
|
+
|
|
130
|
+
Add the following entry to an existing pre-commit configuration after arranging
|
|
131
|
+
installation of the selected CLI version:
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
repos:
|
|
135
|
+
- repo: local
|
|
136
|
+
hooks:
|
|
137
|
+
- id: macrostates
|
|
138
|
+
name: Check staged Macrostates specifications
|
|
139
|
+
entry: macrostates check --staged
|
|
140
|
+
language: system
|
|
141
|
+
pass_filenames: false
|
|
142
|
+
always_run: true
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Run `macrostates check` in CI too. The CLI does not install hooks or change Git
|
|
146
|
+
settings automatically. Staged snapshots currently have a 128 MiB size limit
|
|
147
|
+
and exclude submodule contents. Structural checks do not prove semantic
|
|
148
|
+
consistency or implementation conformance. The local Markdown link checker
|
|
149
|
+
checks file targets, skips fenced code, and does not validate heading anchors
|
|
150
|
+
or implement a complete Markdown parser.
|
|
151
|
+
|
|
152
|
+
## Python API
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from macrostates import Project
|
|
156
|
+
|
|
157
|
+
project = Project.open("/path/to/project")
|
|
158
|
+
print(project.info())
|
|
159
|
+
report = project.check()
|
|
160
|
+
for diagnostic in report.diagnostics:
|
|
161
|
+
print(diagnostic.code, diagnostic.message, diagnostic.path)
|
|
162
|
+
assert report.ok
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Supported root exports: `Project`, `Report`, `Diagnostic`, `MacrostatesError`,
|
|
166
|
+
`GitHubSource`, and `SourceProvider`. `Project.open` and `Project.initialize`
|
|
167
|
+
construct projects; `install`, `lock`, `verify`, `lint`, `check`, and `info` are
|
|
168
|
+
the supported operations. `initialize` accepts a composition dictionary/path
|
|
169
|
+
or a `name` plus ordered `(package_name, version)` selections and a `layout`
|
|
170
|
+
of `modern` or `legacy`. Pass `source=GitHubSource(token=...)` for explicit
|
|
171
|
+
authentication or a `SourceProvider` implementation for another test transport.
|
|
172
|
+
`install(locked=True)` requires unchanged locked selections; `check(staged=True)`
|
|
173
|
+
checks the index. Expected configuration/operation errors raise
|
|
174
|
+
`MacrostatesError`; check failures are returned in `Report.diagnostics`.
|
|
175
|
+
Ordinary file read failures can raise `OSError`. Imports perform no project-local
|
|
176
|
+
or network I/O and do not configure logging. Accessing `__version__` explicitly
|
|
177
|
+
reads installed distribution metadata; it does not read a project declaration. The CLI configures standard logging when explicitly invoked.
|
|
178
|
+
|
|
179
|
+
## Compatibility and development
|
|
180
|
+
|
|
181
|
+
Unversioned compositions use the retained legacy reader. New compositions use
|
|
182
|
+
`schema_version: 1`. Both legacy `specs/` and `.macrostates/specs/` layouts are
|
|
183
|
+
recognized. Existing `git-subtree` compositions can be inspected, linted and
|
|
184
|
+
given an upstream-verified integrity lock without changing subtree history.
|
|
185
|
+
Archive `install` refuses subtree sources; use Git subtree maintenance until an
|
|
186
|
+
explicit migration is requested. Old branch-only/commit selectors need explicit
|
|
187
|
+
tag migration and are reported instead of being silently reinterpreted.
|
|
188
|
+
|
|
189
|
+
Package release versions are independent of format versions. Existing package
|
|
190
|
+
metadata is format 1, as is an explicit `schema_version: 1`. Unknown manifest,
|
|
191
|
+
metadata or lock formats fail clearly. Release policy adapters support Meta
|
|
192
|
+
2.0.x/2.1.x and Process 2.3.x/2.4.x/3.0.x/4.0.x/4.1.x. Modern policies require the modern
|
|
193
|
+
layout; Meta 2 also requires composition format 1. Earlier Meta releases and
|
|
194
|
+
Process 1.x/2.0–2.2 retain their existing checks. Future policy releases receive
|
|
195
|
+
explicit unsupported diagnostics rather than guessed requirements. Process 4's
|
|
196
|
+
feature-branch and PR rules require manual workflow review; CLI checks do not
|
|
197
|
+
verify branch discipline or authorize Git operations.
|
|
198
|
+
|
|
199
|
+
`info` lists directory-scoped specifications under visible component directories;
|
|
200
|
+
`lint` checks their local file links. The scope root is the component containing
|
|
201
|
+
`.macrostates/`. Separately composed subprojects are checked independently.
|
|
202
|
+
Tool/cache/build/temporary and hidden implementation directories are excluded
|
|
203
|
+
from this discovery; inspect their applicable scopes manually. Scope authority,
|
|
204
|
+
semantic requirements and workflow conformance always need specification reading.
|
|
205
|
+
See [architecture](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/implementation/main.md) for adapter extension guidance and
|
|
206
|
+
[project specifications](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/specs/main.md) for this repository's working rules.
|
|
207
|
+
The [CLI specification package](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/specs/051_cli/README.md) defines the
|
|
208
|
+
public library, commands, composition, integrity and versioning contracts;
|
|
209
|
+
[conformance evidence](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/implementation/specification-conformance.md)
|
|
210
|
+
maps those requirements to implementation and verification.
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
uv sync --locked
|
|
214
|
+
uv run ruff check .
|
|
215
|
+
uv run ruff format --check .
|
|
216
|
+
uv run pyright
|
|
217
|
+
uv run pytest --cov=macrostates --cov-report=term-missing
|
|
218
|
+
uv build
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The contributor `uv.lock` is committed for repeatable development and CI.
|
|
222
|
+
Builds go to ignored `dist/`; temporary work goes to `tmp/<activity>/`.
|
|
223
|
+
Automated update planning, workflow commands, release publishing and migrations
|
|
224
|
+
are future features.
|
|
225
|
+
|
|
226
|
+
## This repository's specifications and version
|
|
227
|
+
|
|
228
|
+
The CLI manages its own specification composition under `.macrostates/specs/`,
|
|
229
|
+
using Meta 2.1.0, Process 4.1.0, Repository 3.1.0, Python 2.1.0 and Python-library
|
|
230
|
+
1.1.0 as canonical archive snapshots. Its local CLI requirements remain editable.
|
|
231
|
+
`macrostates check` and `check --staged` validate the same files contributors use.
|
|
232
|
+
This is also a real integration test of the supported package installation path.
|
|
233
|
+
|
|
234
|
+
The implementation's single version declaration is
|
|
235
|
+
[release.yaml](https://github.com/Macrostates/macrostates-cli/blob/main/.macrostates/implementation/release.yaml); the specification baseline
|
|
236
|
+
is `project.version` in the composition. Setuptools reads the declaration during
|
|
237
|
+
isolated builds. The sdist includes that one declaration, while the wheel reports
|
|
238
|
+
its installed distribution version. Builds do not edit declarations, create tags
|
|
239
|
+
or require Git/network access to obtain release metadata. Ordinary dependency
|
|
240
|
+
installation may still require access to package indexes.
|
|
241
|
+
|
|
242
|
+
## AI assistance
|
|
243
|
+
|
|
244
|
+
This project was developed with AI assistance.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "PyYAML>=6.0.2,<7"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "macrostates-cli"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Compose, install and validate versioned Macrostates specification packages."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{name = "Lucas Lopez", email = "713375+lucaslopez@users.noreply.github.com"}]
|
|
14
|
+
dependencies = ["PyYAML>=6.0.2,<7"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Repository = "https://github.com/Macrostates/macrostates-cli"
|
|
18
|
+
Documentation = "https://github.com/Macrostates/macrostates-cli#readme"
|
|
19
|
+
Issues = "https://github.com/Macrostates/macrostates-cli/issues"
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
macrostates = "macrostates._cli:main"
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = ["pytest>=8", "pytest-cov>=6", "ruff>=0.9", "pyright>=1.1.390", "types-PyYAML>=6"]
|
|
26
|
+
|
|
27
|
+
[tool.uv]
|
|
28
|
+
cache-keys = [
|
|
29
|
+
{file = "pyproject.toml"},
|
|
30
|
+
{file = ".macrostates/implementation/release.yaml"},
|
|
31
|
+
{file = "README.md"},
|
|
32
|
+
{dir = "src"},
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["src"]
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.package-data]
|
|
39
|
+
macrostates = ["py.typed"]
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.dynamic]
|
|
42
|
+
version = {attr = "macrostates._build_version.VERSION"}
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
testpaths = ["tests"]
|
|
46
|
+
addopts = "--strict-markers"
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
target-version = "py312"
|
|
50
|
+
line-length = 100
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E4", "E7", "E9", "F", "I", "UP", "B"]
|
|
54
|
+
|
|
55
|
+
[tool.pyright]
|
|
56
|
+
include = ["src", "examples"]
|
|
57
|
+
pythonVersion = "3.12"
|
|
58
|
+
typeCheckingMode = "standard"
|
|
59
|
+
venvPath = "."
|
|
60
|
+
venv = ".venv"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""The public API. Imports perform no network or project-local file access."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from ._models import Diagnostic, MacrostatesError, Report
|
|
6
|
+
from ._project import Project
|
|
7
|
+
from ._sources import GitHubSource, SourceProvider
|
|
8
|
+
|
|
9
|
+
__all__ = ["Diagnostic", "GitHubSource", "MacrostatesError", "Project", "Report", "SourceProvider"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def __getattr__(name: str) -> str:
|
|
13
|
+
if name != "__version__":
|
|
14
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
15
|
+
# Read distribution metadata only when a caller explicitly requests a version.
|
|
16
|
+
try:
|
|
17
|
+
return version("macrostates-cli")
|
|
18
|
+
except PackageNotFoundError:
|
|
19
|
+
return "0+uninstalled"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def __dir__() -> list[str]:
|
|
23
|
+
return sorted([*globals(), "__version__"])
|