system-spec-ref 0.1.0__py3-none-any.whl
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.
- system_spec_ref/__init__.py +1 -0
- system_spec_ref/cli.py +117 -0
- system_spec_ref/metamodel.py +614 -0
- system_spec_ref/toolkit/.github/skills/alloy/SKILL.md +49 -0
- system_spec_ref/toolkit/.github/skills/modelable/SKILL.md +61 -0
- system_spec_ref/toolkit/.github/skills/tla/SKILL.md +49 -0
- system_spec_ref/toolkit/.github/workflows/metamodel.yml +51 -0
- system_spec_ref/toolkit/BROWNFIELD.md +81 -0
- system_spec_ref/toolkit/CONSTITUTION.md +205 -0
- system_spec_ref/toolkit/GREENFIELD.md +86 -0
- system_spec_ref/toolkit/LICENSE +21 -0
- system_spec_ref/toolkit/PACKAGING.md +120 -0
- system_spec_ref/toolkit/PLAN.md +85 -0
- system_spec_ref/toolkit/README.md +77 -0
- system_spec_ref/toolkit/WIRING.md +49 -0
- system_spec_ref/toolkit/archive/BENCHMARK.md +67 -0
- system_spec_ref/toolkit/archive/README.md +8 -0
- system_spec_ref/toolkit/archive/REVIEW.md +321 -0
- system_spec_ref/toolkit/archive/feedback/modelable-onboarding.md +119 -0
- system_spec_ref/toolkit/archive/feedback/observable-onboarding.md +52 -0
- system_spec_ref/toolkit/examples/brownfield/README.md +93 -0
- system_spec_ref/toolkit/examples/brownfield/level0.yaml +12 -0
- system_spec_ref/toolkit/examples/brownfield/level1.yaml +58 -0
- system_spec_ref/toolkit/examples/brownfield/old.yaml +65 -0
- system_spec_ref/toolkit/examples/brownfield/spec.yaml +85 -0
- system_spec_ref/toolkit/examples/greenfield/Inventory.als +72 -0
- system_spec_ref/toolkit/examples/greenfield/Inventory.cfg +7 -0
- system_spec_ref/toolkit/examples/greenfield/Inventory.tla +49 -0
- system_spec_ref/toolkit/examples/greenfield/README.md +79 -0
- system_spec_ref/toolkit/examples/greenfield/spec.yaml +91 -0
- system_spec_ref/toolkit/packaging.yaml +294 -0
- system_spec_ref/toolkit/reference-implementation/.dockerignore +3 -0
- system_spec_ref/toolkit/reference-implementation/.gitignore +3 -0
- system_spec_ref/toolkit/reference-implementation/Dockerfile +7 -0
- system_spec_ref/toolkit/reference-implementation/README.md +44 -0
- system_spec_ref/toolkit/reference-implementation/corpus.yaml +86 -0
- system_spec_ref/toolkit/reference-implementation/example.yaml +89 -0
- system_spec_ref/toolkit/reference-implementation/metamodel.als +133 -0
- system_spec_ref/toolkit/reference-implementation/metamodel.py +614 -0
- system_spec_ref/toolkit/reference-implementation/old.yaml +63 -0
- system_spec_ref/toolkit/reference-implementation/pyproject.toml +16 -0
- system_spec_ref/toolkit/reference-implementation/schema.json +1087 -0
- system_spec_ref/toolkit/reference-implementation/test_metamodel.py +251 -0
- system_spec_ref/toolkit/reference-implementation/test_onboarding.py +142 -0
- system_spec_ref/toolkit/reference-implementation/uv.lock +284 -0
- system_spec_ref/toolkit/spec.md +299 -0
- system_spec_ref/toolkit/templates/BROWNFIELD-INTAKE.md +109 -0
- system_spec_ref-0.1.0.dist-info/METADATA +35 -0
- system_spec_ref-0.1.0.dist-info/RECORD +52 -0
- system_spec_ref-0.1.0.dist-info/WHEEL +4 -0
- system_spec_ref-0.1.0.dist-info/entry_points.txt +2 -0
- system_spec_ref-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
system_spec_ref/cli.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import argparse, importlib.resources, os, shutil, sys, tempfile
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from . import metamodel
|
|
6
|
+
|
|
7
|
+
PACKAGE = "system_spec_ref"
|
|
8
|
+
DIST_NAME = "system-spec-ref"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ExportError(Exception):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _iter_resource_files(root, prefix: str = ""):
|
|
16
|
+
for entry in sorted(root.iterdir(), key=lambda e: e.name):
|
|
17
|
+
rel = f"{prefix}{entry.name}"
|
|
18
|
+
if entry.is_dir():
|
|
19
|
+
yield from _iter_resource_files(entry, rel + "/")
|
|
20
|
+
else:
|
|
21
|
+
yield rel, entry
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _validate_entry(rel: str) -> None:
|
|
25
|
+
if rel.startswith("/") or Path(rel).is_absolute():
|
|
26
|
+
raise ExportError(f"unsafe resource entry (absolute path): {rel}")
|
|
27
|
+
if ".." in Path(rel).parts:
|
|
28
|
+
raise ExportError(f"unsafe resource entry (parent traversal): {rel}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _cleanup_stage(stage: Path) -> None:
|
|
32
|
+
try:
|
|
33
|
+
shutil.rmtree(stage)
|
|
34
|
+
except OSError as e:
|
|
35
|
+
print(f"warning: failed to clean up staging directory {stage}: {e}", file=sys.stderr)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def export_toolkit(destination: str | Path, *, package: str = PACKAGE) -> Path:
|
|
39
|
+
dest = Path(destination)
|
|
40
|
+
if not dest.is_absolute():
|
|
41
|
+
dest = Path.cwd() / dest
|
|
42
|
+
if dest.is_symlink() or dest.exists():
|
|
43
|
+
raise ExportError(f"destination already exists: {dest}")
|
|
44
|
+
parent = dest.parent
|
|
45
|
+
if not parent.is_dir():
|
|
46
|
+
raise ExportError(f"parent directory does not exist: {parent}")
|
|
47
|
+
|
|
48
|
+
toolkit_root = importlib.resources.files(package) / "toolkit"
|
|
49
|
+
entries = []
|
|
50
|
+
for rel, entry in _iter_resource_files(toolkit_root):
|
|
51
|
+
if hasattr(entry, "is_symlink") and entry.is_symlink():
|
|
52
|
+
raise ExportError(f"unsafe resource entry (symlink): {rel}")
|
|
53
|
+
_validate_entry(rel)
|
|
54
|
+
entries.append((rel, entry))
|
|
55
|
+
|
|
56
|
+
stage = Path(tempfile.mkdtemp(prefix=f".{dest.name}.staging-", dir=parent))
|
|
57
|
+
stage_resolved = str(stage.resolve())
|
|
58
|
+
try:
|
|
59
|
+
for rel, entry in entries:
|
|
60
|
+
dest_path = stage / rel
|
|
61
|
+
if not str(dest_path.resolve()).startswith(stage_resolved + os.sep):
|
|
62
|
+
raise ExportError(f"unsafe resource entry escapes staging area: {rel}")
|
|
63
|
+
dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
64
|
+
with entry.open("rb") as src, open(dest_path, "wb") as out:
|
|
65
|
+
shutil.copyfileobj(src, out)
|
|
66
|
+
except Exception as e:
|
|
67
|
+
_cleanup_stage(stage)
|
|
68
|
+
raise ExportError(str(e)) from e
|
|
69
|
+
|
|
70
|
+
if dest.is_symlink() or dest.exists():
|
|
71
|
+
_cleanup_stage(stage)
|
|
72
|
+
raise ExportError(f"destination already exists: {dest}")
|
|
73
|
+
try:
|
|
74
|
+
os.mkdir(dest)
|
|
75
|
+
except OSError as e:
|
|
76
|
+
_cleanup_stage(stage)
|
|
77
|
+
raise ExportError(f"destination already exists: {dest}") from e
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
for child in stage.iterdir():
|
|
81
|
+
shutil.move(str(child), str(dest / child.name))
|
|
82
|
+
stage.rmdir()
|
|
83
|
+
except Exception as e:
|
|
84
|
+
raise ExportError(f"publish failed after claiming destination {dest}: {e}") from e
|
|
85
|
+
return dest
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _run_export(argv: list[str]) -> int:
|
|
89
|
+
ap = argparse.ArgumentParser(prog="system-spec export", description="Export an offline toolkit snapshot.")
|
|
90
|
+
ap.add_argument("destination")
|
|
91
|
+
a = ap.parse_args(argv)
|
|
92
|
+
try:
|
|
93
|
+
dest = export_toolkit(a.destination)
|
|
94
|
+
except ExportError as e:
|
|
95
|
+
print(f"export failed: {e}", file=sys.stderr)
|
|
96
|
+
return 1
|
|
97
|
+
print(f"exported toolkit {metamodel.package_version(DIST_NAME)} to {dest}")
|
|
98
|
+
print(f"next: read {dest / 'WIRING.md'} to wire it into your project and agents")
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _run_validate(argv: list[str]) -> int:
|
|
103
|
+
version = metamodel.package_version(DIST_NAME)
|
|
104
|
+
resource = importlib.resources.files(PACKAGE) / "toolkit" / "reference-implementation" / "example.yaml"
|
|
105
|
+
with importlib.resources.as_file(resource) as default_path:
|
|
106
|
+
return metamodel.main(argv, default_spec=default_path, version=version)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def run(argv: list[str] | None = None) -> int:
|
|
110
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
111
|
+
if argv and argv[0] == "export":
|
|
112
|
+
return _run_export(argv[1:])
|
|
113
|
+
return _run_validate(argv)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
sys.exit(run())
|