urisys 0.1.11__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 (31) hide show
  1. urisys-0.1.11/PKG-INFO +161 -0
  2. urisys-0.1.11/README.md +133 -0
  3. urisys-0.1.11/pyproject.toml +103 -0
  4. urisys-0.1.11/setup.cfg +4 -0
  5. urisys-0.1.11/src/urisys/__init__.py +3 -0
  6. urisys-0.1.11/src/urisys/cli.py +176 -0
  7. urisys-0.1.11/src/urisys/controllers/__init__.py +0 -0
  8. urisys-0.1.11/src/urisys/controllers/flow_controller.py +33 -0
  9. urisys-0.1.11/src/urisys/controllers/server_controller.py +18 -0
  10. urisys-0.1.11/src/urisys/controllers/uri_controller.py +33 -0
  11. urisys-0.1.11/src/urisys/defaults.py +18 -0
  12. urisys-0.1.11/src/urisys/flow.py +25 -0
  13. urisys-0.1.11/src/urisys/http_server.py +78 -0
  14. urisys-0.1.11/src/urisys/managers/__init__.py +0 -0
  15. urisys-0.1.11/src/urisys/managers/bridge_manager.py +14 -0
  16. urisys-0.1.11/src/urisys/managers/event_manager.py +13 -0
  17. urisys-0.1.11/src/urisys/managers/markpact_manager.py +579 -0
  18. urisys-0.1.11/src/urisys/managers/pack_manager.py +97 -0
  19. urisys-0.1.11/src/urisys/managers/policy_manager.py +18 -0
  20. urisys-0.1.11/src/urisys/managers/route_manager.py +23 -0
  21. urisys-0.1.11/src/urisys/managers/runtime_manager.py +30 -0
  22. urisys-0.1.11/src/urisys/managers/source_manager.py +224 -0
  23. urisys-0.1.11/src/urisys.egg-info/PKG-INFO +161 -0
  24. urisys-0.1.11/src/urisys.egg-info/SOURCES.txt +29 -0
  25. urisys-0.1.11/src/urisys.egg-info/dependency_links.txt +1 -0
  26. urisys-0.1.11/src/urisys.egg-info/entry_points.txt +2 -0
  27. urisys-0.1.11/src/urisys.egg-info/requires.txt +14 -0
  28. urisys-0.1.11/src/urisys.egg-info/top_level.txt +1 -0
  29. urisys-0.1.11/tests/test_markpact.py +80 -0
  30. urisys-0.1.11/tests/test_source_manager.py +35 -0
  31. urisys-0.1.11/tests/test_urisys.py +24 -0
urisys-0.1.11/PKG-INFO ADDED
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: urisys
3
+ Version: 0.1.11
4
+ Summary: URI control system managers/controllers over separate uri* capability packs.
5
+ Author: urisys contributors
6
+ Author-email: Tom Sapletta <tom@sapletta.com>
7
+ License-Expression: Apache-2.0
8
+ Keywords: uri,control-plane,controllers,managers,devices,services
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: uricore>=0.1.0
17
+ Requires-Dist: PyYAML>=6.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest>=8.0; extra == "dev"
20
+ Requires-Dist: uricore; extra == "dev"
21
+ Requires-Dist: uribrowser; extra == "dev"
22
+ Requires-Dist: uridocker; extra == "dev"
23
+ Requires-Dist: goal>=2.1.0; extra == "dev"
24
+ Requires-Dist: costs>=0.1.20; extra == "dev"
25
+ Requires-Dist: pfix>=0.1.60; extra == "dev"
26
+ Provides-Extra: lab
27
+ Requires-Dist: uri2flow>=0.1.2; extra == "lab"
28
+
29
+ # urisys
30
+
31
+
32
+ ## AI Cost Tracking
33
+
34
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.1.11-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
35
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.93-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-8.9h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
36
+
37
+ - 🤖 **LLM usage:** $3.9320 (19 commits)
38
+ - 👤 **Human dev:** ~$891 (8.9h @ $100/h, 30min dedup)
39
+
40
+ Generated on 2026-06-16 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
41
+
42
+ ---
43
+
44
+ Centralny **URI control plane** dla TellMesh: CLI (`urisys`), managers, Markpact oraz monorepo obrazów Docker z edge runtime.
45
+
46
+ ## Instalacja
47
+
48
+ ```bash
49
+ pip install urisys
50
+ ```
51
+
52
+ ### Dev (checkout tellmesh)
53
+
54
+ Wymaga checkout **tellmesh** (urisys obok `uricore/`, `uri-packs/`, opcjonalnie `nl2uri/`, `uri2flow/`).
55
+
56
+ ```bash
57
+ cd tellmesh/urisys
58
+
59
+ # wirtualne środowisko (poprawna składnia — NIE komenda `venv`)
60
+ python3 -m venv .venv
61
+ source .venv/bin/activate
62
+
63
+ # zalecane: uv (lockfile)
64
+ uv sync
65
+
66
+ # alternatywa bez uv:
67
+ pip install -e ".[dev]"
68
+ pip install -e ../uricore # sibling w tellmesh workspace
69
+ ```
70
+
71
+ Po instalacji CLI:
72
+
73
+ ```bash
74
+ urisys --help
75
+ which urisys # → .venv/bin/urisys
76
+ ```
77
+
78
+ Zależności runtime: **`uricore`** (PyPI `uricore>=0.1.2` lub editable `../uricore`), paczki URI z **`uri-packs`** (dev group w `pyproject.toml`).
79
+
80
+ ## Szybki start
81
+
82
+ ```bash
83
+ cd urisys && uv sync
84
+
85
+ # Pojedyncze URI (paczki z uri-packs)
86
+ urisys --packs browser call browser://default/page/open \
87
+ --payload '{"url":"https://example.com"}' --approve
88
+
89
+ # Flow mock
90
+ urisys --packs all flow flows/device-maintenance.uri.flow.yaml --approve --dry-run
91
+
92
+ # HTTP server
93
+ urisys --packs all serve --port 8789
94
+ ```
95
+
96
+ ## Docker lab (10 automatyzacji + RDP)
97
+
98
+ ```bash
99
+ cd urisys-automation-lab
100
+ bash scripts/docker-up.sh
101
+ bash scripts/docker-smoke.sh
102
+
103
+ # Pełny test E2E
104
+ python3 scripts/run_test_sessions.py --sessions lab-10-flows
105
+ # lub: bash scripts/run-lab-e2e.sh
106
+ ```
107
+
108
+ ## Dokumentacja
109
+
110
+ | Dokument | Temat |
111
+ |----------|--------|
112
+ | [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Jak działa urisys — warstwy, runtime, testy |
113
+ | [`docs/PACKAGES.md`](docs/PACKAGES.md) | Layout monorepo, duplikaty, plan konsolidacji |
114
+ | [`docs/FLOWS.md`](docs/FLOWS.md) | URI flows, zależności, walidacja |
115
+ | [`docs/EXAMPLES.md`](docs/EXAMPLES.md) | Przykłady shell/frontend/Docker |
116
+ | [`docs/CLI.md`](docs/CLI.md) | Komendy CLI |
117
+ | [`docs/MARKPACT.md`](docs/MARKPACT.md) | Markpact validate/compile/test |
118
+ | [`project/MAP.md`](project/MAP.md) | Przewodnik po `map.toon.yaml` (code2llm) |
119
+ | [`project/PACKAGES.md`](project/PACKAGES.md) | Indeks paczek sync z mapÄ… |
120
+
121
+ ## Struktura monorepo
122
+
123
+ ```text
124
+ src/urisys/ pip package — CLI + managers
125
+ packages/python/urisysedge/ wspólny edge runtime (canonical)
126
+ urirdp-docker/ RDP + KVM/HIM/OCR/LLM/shell/browser
127
+ urisys-automation-lab/ 10 flows, lab UI :8099
128
+ urisys-node/ slave node + ArtifactResolver
129
+ local-lab/ markpact.com release chain
130
+ flows/ przykład flow dla CLI
131
+ examples/ shell + frontend
132
+ markpacts/packs/ Markpact do walidacji
133
+ scripts/ test sessions, validate-all-markpacts
134
+ ```
135
+
136
+ ## Managers
137
+
138
+ - `PackManager` — paczki `uri*`, manifest.yaml, Markpact
139
+ - `MarkpactManager` — validate / compile / test `*.markpact.md`
140
+ - `RuntimeManager` — `uri_control.UriControlRuntime`
141
+ - `UriController` — call, explain, routes
142
+ - `FlowController` — sekwencyjne `*.uri.flow.yaml`
143
+ - `BridgeManager` — forward do zdalnego `/uri/call`
144
+
145
+ ## Markpact
146
+
147
+ ```bash
148
+ urisys markpact validate markpacts/packs/uribrowser.markpact.md
149
+ bash scripts/validate-all-markpacts.sh
150
+ ```
151
+
152
+ ## Analiza projektu (code2llm)
153
+
154
+ ```bash
155
+ code2llm ./ -f all -o ./project
156
+ # → project/map.toon.yaml, calls.mmd, context.md
157
+ ```
158
+
159
+ ## License
160
+
161
+ Licensed under Apache-2.0.
@@ -0,0 +1,133 @@
1
+ # urisys
2
+
3
+
4
+ ## AI Cost Tracking
5
+
6
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.1.11-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.93-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-8.9h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
8
+
9
+ - 🤖 **LLM usage:** $3.9320 (19 commits)
10
+ - 👤 **Human dev:** ~$891 (8.9h @ $100/h, 30min dedup)
11
+
12
+ Generated on 2026-06-16 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
13
+
14
+ ---
15
+
16
+ Centralny **URI control plane** dla TellMesh: CLI (`urisys`), managers, Markpact oraz monorepo obrazów Docker z edge runtime.
17
+
18
+ ## Instalacja
19
+
20
+ ```bash
21
+ pip install urisys
22
+ ```
23
+
24
+ ### Dev (checkout tellmesh)
25
+
26
+ Wymaga checkout **tellmesh** (urisys obok `uricore/`, `uri-packs/`, opcjonalnie `nl2uri/`, `uri2flow/`).
27
+
28
+ ```bash
29
+ cd tellmesh/urisys
30
+
31
+ # wirtualne środowisko (poprawna składnia — NIE komenda `venv`)
32
+ python3 -m venv .venv
33
+ source .venv/bin/activate
34
+
35
+ # zalecane: uv (lockfile)
36
+ uv sync
37
+
38
+ # alternatywa bez uv:
39
+ pip install -e ".[dev]"
40
+ pip install -e ../uricore # sibling w tellmesh workspace
41
+ ```
42
+
43
+ Po instalacji CLI:
44
+
45
+ ```bash
46
+ urisys --help
47
+ which urisys # → .venv/bin/urisys
48
+ ```
49
+
50
+ Zależności runtime: **`uricore`** (PyPI `uricore>=0.1.2` lub editable `../uricore`), paczki URI z **`uri-packs`** (dev group w `pyproject.toml`).
51
+
52
+ ## Szybki start
53
+
54
+ ```bash
55
+ cd urisys && uv sync
56
+
57
+ # Pojedyncze URI (paczki z uri-packs)
58
+ urisys --packs browser call browser://default/page/open \
59
+ --payload '{"url":"https://example.com"}' --approve
60
+
61
+ # Flow mock
62
+ urisys --packs all flow flows/device-maintenance.uri.flow.yaml --approve --dry-run
63
+
64
+ # HTTP server
65
+ urisys --packs all serve --port 8789
66
+ ```
67
+
68
+ ## Docker lab (10 automatyzacji + RDP)
69
+
70
+ ```bash
71
+ cd urisys-automation-lab
72
+ bash scripts/docker-up.sh
73
+ bash scripts/docker-smoke.sh
74
+
75
+ # Pełny test E2E
76
+ python3 scripts/run_test_sessions.py --sessions lab-10-flows
77
+ # lub: bash scripts/run-lab-e2e.sh
78
+ ```
79
+
80
+ ## Dokumentacja
81
+
82
+ | Dokument | Temat |
83
+ |----------|--------|
84
+ | [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Jak działa urisys — warstwy, runtime, testy |
85
+ | [`docs/PACKAGES.md`](docs/PACKAGES.md) | Layout monorepo, duplikaty, plan konsolidacji |
86
+ | [`docs/FLOWS.md`](docs/FLOWS.md) | URI flows, zależności, walidacja |
87
+ | [`docs/EXAMPLES.md`](docs/EXAMPLES.md) | Przykłady shell/frontend/Docker |
88
+ | [`docs/CLI.md`](docs/CLI.md) | Komendy CLI |
89
+ | [`docs/MARKPACT.md`](docs/MARKPACT.md) | Markpact validate/compile/test |
90
+ | [`project/MAP.md`](project/MAP.md) | Przewodnik po `map.toon.yaml` (code2llm) |
91
+ | [`project/PACKAGES.md`](project/PACKAGES.md) | Indeks paczek sync z mapÄ… |
92
+
93
+ ## Struktura monorepo
94
+
95
+ ```text
96
+ src/urisys/ pip package — CLI + managers
97
+ packages/python/urisysedge/ wspólny edge runtime (canonical)
98
+ urirdp-docker/ RDP + KVM/HIM/OCR/LLM/shell/browser
99
+ urisys-automation-lab/ 10 flows, lab UI :8099
100
+ urisys-node/ slave node + ArtifactResolver
101
+ local-lab/ markpact.com release chain
102
+ flows/ przykład flow dla CLI
103
+ examples/ shell + frontend
104
+ markpacts/packs/ Markpact do walidacji
105
+ scripts/ test sessions, validate-all-markpacts
106
+ ```
107
+
108
+ ## Managers
109
+
110
+ - `PackManager` — paczki `uri*`, manifest.yaml, Markpact
111
+ - `MarkpactManager` — validate / compile / test `*.markpact.md`
112
+ - `RuntimeManager` — `uri_control.UriControlRuntime`
113
+ - `UriController` — call, explain, routes
114
+ - `FlowController` — sekwencyjne `*.uri.flow.yaml`
115
+ - `BridgeManager` — forward do zdalnego `/uri/call`
116
+
117
+ ## Markpact
118
+
119
+ ```bash
120
+ urisys markpact validate markpacts/packs/uribrowser.markpact.md
121
+ bash scripts/validate-all-markpacts.sh
122
+ ```
123
+
124
+ ## Analiza projektu (code2llm)
125
+
126
+ ```bash
127
+ code2llm ./ -f all -o ./project
128
+ # → project/map.toon.yaml, calls.mmd, context.md
129
+ ```
130
+
131
+ ## License
132
+
133
+ Licensed under Apache-2.0.
@@ -0,0 +1,103 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "urisys"
7
+ version = "0.1.11"
8
+ description = "URI control system managers/controllers over separate uri* capability packs."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "Apache-2.0"
12
+ authors = [
13
+ { name = "urisys contributors" },
14
+ { name = "Tom Sapletta", email = "tom@sapletta.com" },
15
+ ]
16
+ dependencies = ["uricore>=0.1.0", "PyYAML>=6.0"]
17
+ keywords = ["uri", "control-plane", "controllers", "managers", "devices", "services"]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+ dev = [
28
+ "pytest>=8.0",
29
+ "uricore",
30
+ "uribrowser",
31
+ "uridocker",
32
+ "goal>=2.1.0",
33
+ "costs>=0.1.20",
34
+ "pfix>=0.1.60",
35
+ ]
36
+ lab = [
37
+ "uri2flow>=0.1.2",
38
+ ]
39
+
40
+ [dependency-groups]
41
+ dev = [
42
+ "pytest>=8.0",
43
+ "uricore",
44
+ "uribrowser",
45
+ "uridocker",
46
+ ]
47
+ lab = [
48
+ "uri2flow>=0.1.2",
49
+ ]
50
+
51
+ [tool.uv.sources]
52
+ uricore = { path = "../uricore", editable = true }
53
+ uribrowser = { path = "../uri-packs/packages/python/uribrowser", editable = true }
54
+ uridocker = { path = "../uri-packs/packages/python/uridocker", editable = true }
55
+ uri2flow = { path = "../uri2flow", editable = true }
56
+ uri2ops = { path = "../uri2ops", editable = true }
57
+ uri3 = { path = "../uri3", editable = true }
58
+
59
+ [tool.uv]
60
+ default-groups = ["dev"]
61
+
62
+ [project.scripts]
63
+ urisys = "urisys.cli:main"
64
+
65
+ [tool.setuptools]
66
+ package-dir = {"" = "src"}
67
+
68
+ [tool.setuptools.packages.find]
69
+ where = ["src"]
70
+ include = ["urisys*"]
71
+
72
+ [tool.pytest.ini_options]
73
+ pythonpath = ["src"]
74
+ testpaths = ["tests"]
75
+
76
+ [tool.pfix]
77
+ # Self-healing Python configuration
78
+ model = "openrouter/qwen/qwen3-coder-next"
79
+ auto_apply = true
80
+ auto_install_deps = true
81
+ auto_restart = false
82
+ max_retries = 3
83
+ create_backups = false
84
+ git_auto_commit = false
85
+
86
+ [tool.pfix.runtime_todo]
87
+ enabled = true
88
+ todo_file = "TODO.md"
89
+ min_severity = "low"
90
+ deduplicate = true
91
+
92
+ [tool.costs]
93
+ # AI Cost tracking configuration
94
+ badge = true
95
+ update_readme = true
96
+ readme_path = "README.md"
97
+ default_model = "openrouter/qwen/qwen3-coder-next"
98
+ analysis_mode = "byok"
99
+ full_history = true
100
+ max_commits = 500
101
+
102
+ # Cost thresholds for badge colors (USD)
103
+ badge_color_thresholds = { low = 1.0, medium = 5.0, high = 10.0, critical = 50.0 }
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from __future__ import annotations
2
+
3
+ __version__ = "0.1.11"
@@ -0,0 +1,176 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from pathlib import Path
6
+
7
+ from uri_control import CapabilityRegistry
8
+
9
+ from .defaults import DEFAULT_ENVIRONMENT
10
+ from .controllers.flow_controller import FlowController
11
+ from .controllers.server_controller import ServerController
12
+ from .controllers.uri_controller import UriController
13
+ from .managers.event_manager import EventManager
14
+ from .managers.markpact_manager import MarkpactManager, MarkpactError
15
+ from .managers.source_manager import SourceManager, SourceError
16
+
17
+
18
+ def _json_arg(value: str | None) -> dict:
19
+ if not value:
20
+ return {}
21
+ if value.startswith("@"):
22
+ return json.loads(Path(value[1:]).read_text(encoding="utf-8"))
23
+ return json.loads(value)
24
+
25
+
26
+ def print_json(data: dict) -> None:
27
+ print(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True))
28
+
29
+
30
+ def _add_runtime_flags(parser: argparse.ArgumentParser) -> None:
31
+ parser.add_argument("--approve", action="store_true")
32
+ parser.add_argument("--dry-run", action="store_true")
33
+ parser.add_argument("--allow-real", action="store_true")
34
+ parser.add_argument("--environment", default=DEFAULT_ENVIRONMENT)
35
+
36
+
37
+ def resolve_markpact_source(source: str, *, source_manager: SourceManager | None = None) -> str:
38
+ manager = source_manager or SourceManager()
39
+ return str(manager.resolve(source))
40
+
41
+
42
+ def build_parser() -> argparse.ArgumentParser:
43
+ parser = argparse.ArgumentParser(prog="urisys", description="URI control system: managers/controllers over uri* packs and UriPack Markpacts.")
44
+ parser.add_argument("--packs", default="all", help="Comma-separated pack aliases/packages, plain manifest paths, Markpact paths or all/none.")
45
+ parser.add_argument("--markpact", action="append", default=[], help="Load one UriPack Markpact. Can be used multiple times.")
46
+ parser.add_argument("--events", default="output/urisys-events.jsonl")
47
+ sub = parser.add_subparsers(dest="command", required=True)
48
+
49
+ p = sub.add_parser("call", help="Execute a URI through urisys.")
50
+ p.add_argument("uri")
51
+ p.add_argument("--payload", default="{}", help="JSON payload or @file.json")
52
+ _add_runtime_flags(p)
53
+
54
+ p = sub.add_parser("explain", help="Explain how a URI routes.")
55
+ p.add_argument("uri")
56
+
57
+ sub.add_parser("routes", help="List loaded routes.")
58
+ sub.add_parser("events", help="List event log.")
59
+
60
+ p = sub.add_parser("flow", help="Run a compact URI flow YAML.")
61
+ p.add_argument("path")
62
+ _add_runtime_flags(p)
63
+
64
+ p = sub.add_parser("serve", help="Run HTTP URI server.")
65
+ p.add_argument("--host", default="127.0.0.1")
66
+ p.add_argument("--port", type=int, default=8789)
67
+
68
+ p = sub.add_parser("markpact", help="Validate, compile, fetch and test one-file UriPack Markpacts.")
69
+ msub = p.add_subparsers(dest="markpact_command", required=True)
70
+
71
+ p_fetch = msub.add_parser("fetch", help="Fetch a Markpact from file/HTTP/GitHub/git/ZIP and cache it locally.")
72
+ p_fetch.add_argument("source")
73
+ p_fetch.add_argument("--force", action="store_true")
74
+
75
+ p_validate = msub.add_parser("validate", help="Validate a Markpact file or remote source.")
76
+ p_validate.add_argument("path")
77
+
78
+ p_compile = msub.add_parser("compile", help="Compile Markpact to cached runtime manifest and handlers.")
79
+ p_compile.add_argument("path")
80
+ p_compile.add_argument("--out", default=None, help="Optional output/cache directory.")
81
+ p_compile.add_argument("--force", action="store_true")
82
+
83
+ p_routes = msub.add_parser("routes", help="Compile Markpact and list generated routes.")
84
+ p_routes.add_argument("path")
85
+ p_routes.add_argument("--out", default=None)
86
+
87
+ p_test = msub.add_parser("test", help="Run tests embedded in Markpact.")
88
+ p_test.add_argument("path")
89
+ p_test.add_argument("--out", default=None, help="Optional compile/cache directory.")
90
+
91
+ return parser
92
+
93
+
94
+ def main(argv: list[str] | None = None) -> int:
95
+ args = build_parser().parse_args(argv)
96
+
97
+ try:
98
+ if args.command == "markpact":
99
+ source_manager = SourceManager(cache_root=(Path(args.out) / "sources") if getattr(args, "out", None) else ".urisys/cache/sources")
100
+ manager = MarkpactManager(cache_root=args.out) if getattr(args, "out", None) else MarkpactManager()
101
+ if args.markpact_command == "fetch":
102
+ print_json(source_manager.fetch(args.source, force=args.force))
103
+ return 0
104
+ local_path = resolve_markpact_source(args.path, source_manager=source_manager)
105
+ if args.markpact_command == "validate":
106
+ print_json(manager.validate(local_path))
107
+ return 0
108
+ if args.markpact_command == "compile":
109
+ compiled = manager.compile(local_path, out_dir=args.out, force=args.force)
110
+ print_json({"ok": True, "compiled": compiled.to_dict()})
111
+ return 0
112
+ if args.markpact_command == "routes":
113
+ compiled = manager.compile(local_path, out_dir=args.out)
114
+ registry = CapabilityRegistry.from_manifest_files([compiled.manifest_path])
115
+ print_json({
116
+ "ok": True,
117
+ "compiled": compiled.to_dict(),
118
+ "routes": [
119
+ {
120
+ "manifest_id": r.manifest_id,
121
+ "scheme": r.scheme,
122
+ "pattern": r.pattern,
123
+ "kind": r.kind,
124
+ "operation": r.operation,
125
+ "approval": r.approval,
126
+ "side_effects": r.side_effects,
127
+ "handler_ref": r.handler_ref,
128
+ }
129
+ for r in registry.routes
130
+ ],
131
+ })
132
+ return 0
133
+ if args.markpact_command == "test":
134
+ print_json(manager.run_tests(local_path, events_path=args.events))
135
+ return 0
136
+
137
+ if args.command == "serve":
138
+ ServerController(host=args.host, port=args.port, packs=args.packs, markpacts=args.markpact, events_path=args.events).serve_forever()
139
+ return 0
140
+
141
+ if args.command == "flow":
142
+ ctrl = FlowController(packs=args.packs, markpacts=args.markpact, events_path=args.events)
143
+ try:
144
+ print_json(ctrl.run(args.path, approved=args.approve, dry_run=args.dry_run, allow_real=args.allow_real, environment=args.environment))
145
+ finally:
146
+ ctrl.close()
147
+ return 0
148
+
149
+ if args.command == "events":
150
+ print_json({"ok": True, "events": EventManager(args.events).list_events()})
151
+ return 0
152
+
153
+ ctrl = UriController(packs=args.packs, markpacts=args.markpact, events_path=args.events)
154
+ try:
155
+ if args.command == "call":
156
+ print_json(ctrl.call(args.uri, _json_arg(args.payload), approved=args.approve, dry_run=args.dry_run, allow_real=args.allow_real, environment=args.environment))
157
+ return 0
158
+ if args.command == "explain":
159
+ print_json({"ok": True, "explain": ctrl.explain(args.uri)})
160
+ return 0
161
+ if args.command == "routes":
162
+ print_json({"ok": True, "routes": ctrl.routes()})
163
+ return 0
164
+ finally:
165
+ ctrl.close()
166
+ return 1
167
+ except MarkpactError as exc:
168
+ print_json({"ok": False, "error": str(exc), "type": "markpact_error"})
169
+ return 2
170
+ except SourceError as exc:
171
+ print_json({"ok": False, "error": str(exc), "type": "source_error"})
172
+ return 2
173
+
174
+
175
+ if __name__ == "__main__":
176
+ raise SystemExit(main())
File without changes
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from ..defaults import DEFAULT_ENVIRONMENT
6
+ from ..flow import iter_steps, load_flow
7
+ from .uri_controller import UriController
8
+
9
+
10
+ class FlowController:
11
+ def __init__(self, packs="all", *, markpacts=None, events_path: str | None = None) -> None:
12
+ self.uri_controller = UriController(packs=packs, markpacts=markpacts, events_path=events_path)
13
+
14
+ def run(self, path: str | Path, *, approved=False, dry_run=False, allow_real=False, environment=DEFAULT_ENVIRONMENT) -> dict:
15
+ flow = load_flow(path)
16
+ defaults = flow.get("defaults") or {}
17
+ results = []
18
+ for uri, payload in iter_steps(flow):
19
+ result = self.uri_controller.call(
20
+ uri,
21
+ payload,
22
+ approved=bool(defaults.get("approved", approved)),
23
+ dry_run=bool(defaults.get("dry_run", dry_run)),
24
+ allow_real=bool(defaults.get("allow_real", allow_real)),
25
+ environment=str(defaults.get("environment", environment)),
26
+ )
27
+ results.append(result)
28
+ if not result.get("ok") and not bool(defaults.get("continue_on_error")):
29
+ break
30
+ return {"ok": all(r.get("ok") for r in results), "flow": flow.get("flow", {}), "results": results}
31
+
32
+ def close(self) -> None:
33
+ self.uri_controller.close()
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from ..http_server import create_server
4
+
5
+
6
+ class ServerController:
7
+ def __init__(self, *, host="127.0.0.1", port=8789, packs="all", markpacts=None, events_path="output/urisys-events.jsonl") -> None:
8
+ self.host = host
9
+ self.port = port
10
+ self.packs = packs
11
+ self.markpacts = markpacts
12
+ self.events_path = events_path
13
+ self.server = create_server(host, port, packs=packs, markpacts=markpacts, events_path=events_path)
14
+
15
+ def serve_forever(self) -> None:
16
+ print(f"urisys server listening on http://{self.host}:{self.port}")
17
+ print("endpoints: GET /health, GET /uri/routes, GET /uri/events, POST /uri/call, POST /uri/explain")
18
+ self.server.serve_forever()
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from ..defaults import DEFAULT_ENVIRONMENT
4
+ from ..managers.policy_manager import PolicyManager
5
+ from ..managers.route_manager import RouteManager
6
+ from ..managers.runtime_manager import RuntimeManager
7
+
8
+
9
+ class UriController:
10
+ def __init__(self, packs="all", *, markpacts=None, events_path: str | None = None) -> None:
11
+ self.runtime_manager = RuntimeManager(packs, markpacts=markpacts, events_path=events_path)
12
+ self.runtime = self.runtime_manager.create_runtime()
13
+ self.policy_manager = PolicyManager()
14
+ self.route_manager = RouteManager(self.runtime)
15
+
16
+ def call(self, uri: str, payload=None, *, approved=False, dry_run=False, allow_real=False, environment=DEFAULT_ENVIRONMENT, context=None) -> dict:
17
+ ctx = self.policy_manager.build_context(
18
+ approved=approved,
19
+ dry_run=dry_run,
20
+ allow_real=allow_real,
21
+ environment=environment,
22
+ extra=context or {},
23
+ )
24
+ return self.runtime.call(uri, payload or {}, ctx).to_dict()
25
+
26
+ def explain(self, uri: str) -> dict:
27
+ return self.route_manager.explain(uri)
28
+
29
+ def routes(self) -> list[dict]:
30
+ return self.route_manager.list_routes()
31
+
32
+ def close(self) -> None:
33
+ self.runtime_manager.close()