napkinstack 0.9.2__tar.gz → 0.9.4__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 (34) hide show
  1. {napkinstack-0.9.2 → napkinstack-0.9.4}/PKG-INFO +4 -4
  2. {napkinstack-0.9.2 → napkinstack-0.9.4}/README.md +3 -3
  3. {napkinstack-0.9.2 → napkinstack-0.9.4}/pyproject.toml +2 -2
  4. {napkinstack-0.9.2 → napkinstack-0.9.4}/pyproject.toml.orig +2 -2
  5. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/__init__.py +2 -2
  6. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/provenance.py +19 -1
  7. {napkinstack-0.9.2 → napkinstack-0.9.4}/LICENSE +0 -0
  8. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/assurance.py +0 -0
  9. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/cli.py +0 -0
  10. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/compat.py +0 -0
  11. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/discovery.py +0 -0
  12. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/doctor.py +0 -0
  13. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/fitness/__init__.py +0 -0
  14. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/fitness/boundaries.py +0 -0
  15. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/fitness/hygiene.py +0 -0
  16. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/fitness/manifests.py +0 -0
  17. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/fitness/plan.py +0 -0
  18. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/fitness/pr_scope.py +0 -0
  19. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/landed.py +0 -0
  20. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/modules.py +0 -0
  21. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/project.py +0 -0
  22. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/pull_request.py +0 -0
  23. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/settings.py +0 -0
  24. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/skills.py +0 -0
  25. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/contracts/AGENTS.md +0 -0
  26. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/contracts/MANIFEST.yaml +0 -0
  27. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/contracts/README.md +0 -0
  28. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/contracts/docs/runbook.md +0 -0
  29. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/contracts/tests/.gitkeep +0 -0
  30. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/module/AGENTS.md +0 -0
  31. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/module/MANIFEST.yaml +0 -0
  32. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/module/README.md +0 -0
  33. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/module/src/.gitkeep +0 -0
  34. {napkinstack-0.9.2 → napkinstack-0.9.4}/src/napkinstack/templates/module/tests/.gitkeep +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: napkinstack
3
- Version: 0.9.2
3
+ Version: 0.9.4
4
4
  Summary: Engineering framework for several teams and their agents working in one repository: modules, contracts, guardrails in CI.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -20,7 +20,7 @@ modules, contracts, guardrails in CI. On the Django or Rails model, one command
20
20
  the project, which then receives new versions on demand; no application stack is imposed.
21
21
  Positioning and vocabulary: [`PRODUCT.md`](PRODUCT.md) §1.
22
22
 
23
- > **Status: v0.9.2, published** on [PyPI](https://pypi.org/project/napkinstack/).
23
+ > **Status: v0.9.4, published** on [PyPI](https://pypi.org/project/napkinstack/).
24
24
  > What each version changes, engine and project apart: [`CHANGELOG.md`](CHANGELOG.md).
25
25
  > What is open: [`docs/governance/workstreams.md`](docs/governance/workstreams.md).
26
26
 
@@ -84,8 +84,8 @@ To try it without installing anything, or to install it from this repository ins
84
84
  registry — always pinned to a release tag:
85
85
 
86
86
  ```bash
87
- uvx --from "git+https://github.com/NapkinStack/engineering-os@v0.9.2" nstack init my-project
88
- uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.9.2"
87
+ uvx --from "git+https://github.com/NapkinStack/engineering-os@v0.9.4" nstack init my-project
88
+ uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.9.4"
89
89
  ```
90
90
 
91
91
  **Two channels, one published artefact.** The registry publishes: the PyPI artefact of a
@@ -5,7 +5,7 @@ modules, contracts, guardrails in CI. On the Django or Rails model, one command
5
5
  the project, which then receives new versions on demand; no application stack is imposed.
6
6
  Positioning and vocabulary: [`PRODUCT.md`](PRODUCT.md) §1.
7
7
 
8
- > **Status: v0.9.2, published** on [PyPI](https://pypi.org/project/napkinstack/).
8
+ > **Status: v0.9.4, published** on [PyPI](https://pypi.org/project/napkinstack/).
9
9
  > What each version changes, engine and project apart: [`CHANGELOG.md`](CHANGELOG.md).
10
10
  > What is open: [`docs/governance/workstreams.md`](docs/governance/workstreams.md).
11
11
 
@@ -69,8 +69,8 @@ To try it without installing anything, or to install it from this repository ins
69
69
  registry — always pinned to a release tag:
70
70
 
71
71
  ```bash
72
- uvx --from "git+https://github.com/NapkinStack/engineering-os@v0.9.2" nstack init my-project
73
- uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.9.2"
72
+ uvx --from "git+https://github.com/NapkinStack/engineering-os@v0.9.4" nstack init my-project
73
+ uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.9.4"
74
74
  ```
75
75
 
76
76
  **Two channels, one published artefact.** The registry publishes: the PyPI artefact of a
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "napkinstack"
3
- version = "0.9.2"
3
+ version = "0.9.4"
4
4
  description = "Engineering framework for several teams and their agents working in one repository: modules, contracts, guardrails in CI."
5
5
  requires-python = ">=3.12"
6
6
  license = "MIT"
@@ -27,5 +27,5 @@ dev = ["pytest==9.1.1"]
27
27
  required-version = ">=0.12.14,<0.13"
28
28
 
29
29
  [build-system]
30
- requires = ["uv_build>=0.12.14,<0.13"]
30
+ requires = ["uv_build>=0.12.14,<0.14"]
31
31
  build-backend = "uv_build"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "napkinstack"
3
- version = "0.9.2"
3
+ version = "0.9.4"
4
4
  description = "Engineering framework for several teams and their agents working in one repository: modules, contracts, guardrails in CI."
5
5
  requires-python = ">=3.12"
6
6
  license = "MIT"
@@ -23,5 +23,5 @@ dev = ["pytest==9.1.1"]
23
23
  required-version = ">=0.12.14,<0.13"
24
24
 
25
25
  [build-system]
26
- requires = ["uv_build>=0.12.14,<0.13"]
26
+ requires = ["uv_build>=0.12.14,<0.14"]
27
27
  build-backend = "uv_build"
@@ -1,5 +1,5 @@
1
1
  """NapkinStack - engine: fitness functions, skills and module scaffolding."""
2
2
 
3
- from importlib.metadata import version
3
+ from napkinstack.provenance import version
4
4
 
5
- __version__ = version("napkinstack")
5
+ __version__ = version()
@@ -14,6 +14,7 @@ import importlib.metadata
14
14
  import json
15
15
  import re
16
16
  import subprocess
17
+ import tomllib
17
18
  from pathlib import Path
18
19
  from urllib.parse import urlparse
19
20
  from urllib.request import url2pathname
@@ -24,6 +25,23 @@ ANSWERS = ".copier-answers.yml"
24
25
  PUBLISHED = re.compile(r"v\d+\.\d+\.\d+")
25
26
 
26
27
 
28
+ def version() -> str:
29
+ """The engine's version. An editable install's metadata is written once, at install, and the
30
+ checkout moves on: its own pyproject.toml says the version its source is at (D122)."""
31
+ distribution = importlib.metadata.distribution("napkinstack")
32
+ try:
33
+ data = json.loads(distribution.read_text("direct_url.json") or "{}")
34
+ except json.JSONDecodeError: # read at import: a damaged record never stops the engine
35
+ return distribution.version
36
+ if data.get("dir_info", {}).get("editable"):
37
+ source = Path(url2pathname(urlparse(data.get("url", "")).path)) / "pyproject.toml"
38
+ try:
39
+ return str(tomllib.loads(source.read_text(encoding="utf-8"))["project"]["version"])
40
+ except (OSError, KeyError, tomllib.TOMLDecodeError):
41
+ pass
42
+ return distribution.version
43
+
44
+
27
45
  def engine() -> tuple[str, str | None]:
28
46
  """(version, origin): origin is None for a version installed from the registry."""
29
47
  distribution = importlib.metadata.distribution("napkinstack")
@@ -44,7 +62,7 @@ def engine() -> tuple[str, str | None]:
44
62
  path = Path(url2pathname(urlparse(data.get("url", "")).path))
45
63
  commit = subprocess.run(["git", "describe", "--always", "--dirty"], cwd=path,
46
64
  capture_output=True, text=True).stdout.strip() if path.is_dir() else ""
47
- return distribution.version, f"a local checkout at {commit or 'an unknown commit'}"
65
+ return version(), f"a local checkout at {commit or 'an unknown commit'}"
48
66
 
49
67
 
50
68
  def recorded(root: Path) -> str | None:
File without changes