napkinstack 0.19.0__tar.gz → 0.19.2__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.
- {napkinstack-0.19.0 → napkinstack-0.19.2}/PKG-INFO +4 -4
- {napkinstack-0.19.0 → napkinstack-0.19.2}/README.md +3 -3
- {napkinstack-0.19.0 → napkinstack-0.19.2}/pyproject.toml +1 -1
- {napkinstack-0.19.0 → napkinstack-0.19.2}/pyproject.toml.orig +1 -1
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/doctor.py +16 -2
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/project.py +1 -1
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/provenance.py +1 -1
- {napkinstack-0.19.0 → napkinstack-0.19.2}/LICENSE +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/__init__.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/assurance.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/attest.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/board.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/cli.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/compat.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/discovery.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/evidence.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/fitness/__init__.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/fitness/boundaries.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/fitness/hygiene.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/fitness/manifests.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/fitness/plan.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/fitness/pr_scope.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/hold.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/landed.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/modules.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/owners.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/pull_request.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/settings.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/skills.py +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/contracts/AGENTS.md +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/contracts/MANIFEST.yaml +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/contracts/README.md +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/contracts/docs/runbook.md +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/contracts/tests/.gitkeep +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/module/AGENTS.md +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/module/MANIFEST.yaml +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/module/README.md +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/module/src/.gitkeep +0 -0
- {napkinstack-0.19.0 → napkinstack-0.19.2}/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.19.
|
|
3
|
+
Version: 0.19.2
|
|
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
|
|
@@ -21,7 +21,7 @@ modules, contracts, guardrails in CI. On the Django or Rails model, one command
|
|
|
21
21
|
the project, which then receives new versions on demand; no application stack is imposed.
|
|
22
22
|
Positioning and vocabulary: [`PRODUCT.md`](PRODUCT.md) §1.
|
|
23
23
|
|
|
24
|
-
> **Status: v0.19.
|
|
24
|
+
> **Status: v0.19.2, published** on [PyPI](https://pypi.org/project/napkinstack/).
|
|
25
25
|
> What each version changes, engine and project apart: [`CHANGELOG.md`](CHANGELOG.md).
|
|
26
26
|
> What is open: [`docs/governance/workstreams.md`](docs/governance/workstreams.md).
|
|
27
27
|
|
|
@@ -85,8 +85,8 @@ To try it without installing anything, or to install it from this repository ins
|
|
|
85
85
|
registry — always pinned to a release tag:
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
uvx --from "git+https://github.com/NapkinStack/engineering-os@v0.19.
|
|
89
|
-
uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.19.
|
|
88
|
+
uvx --from "git+https://github.com/NapkinStack/engineering-os@v0.19.2" nstack init my-project
|
|
89
|
+
uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.19.2"
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
**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.19.
|
|
8
|
+
> **Status: v0.19.2, 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.19.
|
|
73
|
-
uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.19.
|
|
72
|
+
uvx --from "git+https://github.com/NapkinStack/engineering-os@v0.19.2" nstack init my-project
|
|
73
|
+
uv tool install "napkinstack @ git+https://github.com/NapkinStack/engineering-os@v0.19.2"
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
**Two channels, one published artefact.** The registry publishes: the PyPI artefact of a
|
|
@@ -405,9 +405,23 @@ def _kept_for_a_human(root: Path, shown: str, text: str) -> tuple[str, str]:
|
|
|
405
405
|
if name in UNREAD_OWNERSHIP or name == "none":
|
|
406
406
|
return OK, ("No forge reads it here: who approves what is for people to read, and nothing refuses "
|
|
407
407
|
"an agent's approval of the rest.")
|
|
408
|
+
agents = _agent_identities(root)
|
|
409
|
+
if len(agents) < 2:
|
|
410
|
+
return OK, (f"The history shows {len(agents) or 'no'} agent identit{'y' if len(agents) == 1 else 'ies'}"
|
|
411
|
+
+ (f" ({agents[0]})" if agents else "") + ": an agent never approves what its own identity "
|
|
412
|
+
"pushed, so until another contributor's agent works under an identity of its own, every "
|
|
413
|
+
"change waits for a human, as on approval human.")
|
|
408
414
|
return OK, ""
|
|
409
415
|
|
|
410
416
|
|
|
417
|
+
def _agent_identities(root: Path) -> list[str]:
|
|
418
|
+
"""The bot identities the recent history's commits name, as GitHub's noreply addresses say them."""
|
|
419
|
+
shown = subprocess.run(["git", "log", "-n", "500", "--format=%ae%n%ce"], cwd=root, capture_output=True, text=True)
|
|
420
|
+
found = [address.lower() for address in shown.stdout.split()
|
|
421
|
+
if address.lower().endswith("[bot]@users.noreply.github.com")]
|
|
422
|
+
return list(dict.fromkeys(found))
|
|
423
|
+
|
|
424
|
+
|
|
411
425
|
def _forge(path: str) -> dict | None:
|
|
412
426
|
"""JSON of a public repository's page on the forge, read without a token; None when it does
|
|
413
427
|
not answer."""
|
|
@@ -440,7 +454,7 @@ def _left_behind(answers: dict) -> str | None:
|
|
|
440
454
|
def _workstation(root: Path, answers: dict) -> list[tuple[str, str, str, str]]:
|
|
441
455
|
commit = str(answers.get("_commit") or "")
|
|
442
456
|
project = commit.removeprefix("v")
|
|
443
|
-
install = (f'uv tool install "napkinstack=={project}" --with-executables-from pre-commit'
|
|
457
|
+
install = (f'uv tool install "napkinstack=={project}" --refresh-package napkinstack --with-executables-from pre-commit'
|
|
444
458
|
if PUBLISHED.fullmatch(commit) else "bash .nstack/install-engine.sh")
|
|
445
459
|
results = []
|
|
446
460
|
|
|
@@ -563,7 +577,7 @@ def _newer(answers: dict) -> None:
|
|
|
563
577
|
print(f" NEWER VERSION v{latest} is published; the project is on {commit} — information, not a gap\n"
|
|
564
578
|
f" What it changes: {release_notes(str(answers.get('_src_path') or ''), commit, f'v{latest}')}\n"
|
|
565
579
|
f" To take it, at a cycle's boundary: uv tool install \"napkinstack=={latest}\" "
|
|
566
|
-
"--with-executables-from pre-commit, then nstack update")
|
|
580
|
+
"--refresh-package napkinstack --with-executables-from pre-commit, then nstack update")
|
|
567
581
|
|
|
568
582
|
|
|
569
583
|
def _private(client: GitHub) -> bool:
|
|
@@ -85,7 +85,7 @@ def _explain(exc: Exception, command: str, where: Path, source: str, ref: str) -
|
|
|
85
85
|
# version is not moved by `uv tool upgrade`, which is what a reader tries first.
|
|
86
86
|
return (f"FAIL [{command}] Target version {match[2]} older than the project version ({match[1]}): "
|
|
87
87
|
f"no going back.\n{action}move this workstation forward first — "
|
|
88
|
-
'uv tool install "napkinstack@latest" --with-executables-from pre-commit — '
|
|
88
|
+
'uv tool install "napkinstack@latest" --refresh-package napkinstack --with-executables-from pre-commit — '
|
|
89
89
|
f"or pin the version you want, {match[1]} or newer.")
|
|
90
90
|
if text.startswith("Updating is only supported in git-tracked subprojects"):
|
|
91
91
|
return (f"FAIL [{command}] {where} is not a git repository: the merge relies on "
|
|
@@ -135,4 +135,4 @@ def behind(root: Path) -> str | None:
|
|
|
135
135
|
return None
|
|
136
136
|
return (f"This workstation runs nstack {version}; the project is on {project}. A command it names "
|
|
137
137
|
"may not exist here, and a verdict given here is not CI's.\n"
|
|
138
|
-
f' Action: uv tool install "napkinstack=={wanted}" --with-executables-from pre-commit')
|
|
138
|
+
f' Action: uv tool install "napkinstack=={wanted}" --refresh-package napkinstack --with-executables-from pre-commit')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/contracts/docs/runbook.md
RENAMED
|
File without changes
|
{napkinstack-0.19.0 → napkinstack-0.19.2}/src/napkinstack/templates/contracts/tests/.gitkeep
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|