cf-runtime 0.1.8__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.
cf_runtime/__init__.py ADDED
@@ -0,0 +1,74 @@
1
+ """Local Cogniflow runtime bootstrap and lifecycle provider."""
2
+
3
+ from pathlib import Path
4
+
5
+ from .domain import EnvironmentKind, McpTransport, RuntimeId, SourceKind
6
+ from .manifest import (
7
+ DEFAULT_DEVELOPMENT_FUSEKI_PORT,
8
+ DEFAULT_DEVELOPMENT_MCP_COMMAND,
9
+ DEFAULT_PRODUCTION_FUSEKI_PORT,
10
+ DEFAULT_RUNTIME_VERSION,
11
+ DEFAULT_TOOL_VERSIONS,
12
+ RuntimeManifest,
13
+ development_manifest,
14
+ production_manifest,
15
+ validate_manifest_pair,
16
+ )
17
+ from .paths import CogniflowHome, RuntimePaths
18
+ from .managed_tools import ManagedTools, ManagedToolsError, catalog, normalized_platform
19
+ from .lifecycle import ProductionRuntime
20
+ from .target import (
21
+ RuntimeIdentity,
22
+ RuntimeTarget,
23
+ resolve_runtime_target,
24
+ verify_runtime_target,
25
+ )
26
+
27
+ PACKAGE_DISTRIBUTION = "cf-runtime"
28
+ PYTHON_PACKAGE = "cf_runtime"
29
+ PACKAGE_VERSION = "0.1.8"
30
+
31
+
32
+ def package_root() -> Path:
33
+ return Path(__file__).resolve().parent
34
+
35
+
36
+ def semantics_dir() -> Path:
37
+ return package_root() / "semantics"
38
+
39
+
40
+ def semantic_files() -> tuple[Path, ...]:
41
+ return (semantics_dir() / "package.trig",)
42
+
43
+ __all__ = [
44
+ "CogniflowHome",
45
+ "ManagedTools",
46
+ "ManagedToolsError",
47
+ "ProductionRuntime",
48
+ "DEFAULT_DEVELOPMENT_FUSEKI_PORT",
49
+ "DEFAULT_DEVELOPMENT_MCP_COMMAND",
50
+ "DEFAULT_PRODUCTION_FUSEKI_PORT",
51
+ "DEFAULT_RUNTIME_VERSION",
52
+ "DEFAULT_TOOL_VERSIONS",
53
+ "EnvironmentKind",
54
+ "McpTransport",
55
+ "PACKAGE_DISTRIBUTION",
56
+ "PACKAGE_VERSION",
57
+ "PYTHON_PACKAGE",
58
+ "RuntimeId",
59
+ "RuntimeIdentity",
60
+ "RuntimeManifest",
61
+ "RuntimePaths",
62
+ "RuntimeTarget",
63
+ "SourceKind",
64
+ "development_manifest",
65
+ "production_manifest",
66
+ "package_root",
67
+ "resolve_runtime_target",
68
+ "semantic_files",
69
+ "semantics_dir",
70
+ "validate_manifest_pair",
71
+ "catalog",
72
+ "normalized_platform",
73
+ "verify_runtime_target",
74
+ ]
@@ -0,0 +1,376 @@
1
+ """Versioned JSON-lines bootstrap provider executable."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import base64
6
+ import json
7
+ import re
8
+ from pathlib import Path
9
+ import sys
10
+ from typing import Callable
11
+
12
+ from .domain import RuntimeId
13
+ from .lifecycle import DevelopmentRuntime, ProductionRuntime
14
+ from .locking import LifecycleLockedError
15
+ from .managed_tools import MANAGED_REQUEST_SCHEMA, ManagedTools, ManagedToolsError
16
+ from .paths import CogniflowHome
17
+ from .target import resolve_runtime_target
18
+ from .manifest import RuntimeManifest, production_manifest
19
+ from dataclasses import replace
20
+ from .semantics import recover_stopped as recover_stopped_semantics, register as register_semantics, restore as restore_semantics, status as status_semantics, transition as transition_semantics, uninstall as uninstall_semantics
21
+ from .teardown import attest as attest_teardown, cleanup as cleanup_teardown, finalize as finalize_teardown, plan as plan_teardown, prepare as prepare_teardown, recover as recover_teardown, stop as stop_teardown
22
+
23
+ JSONRPC = "2.0"
24
+ PROTOCOL = "cf.runtime.bootstrap.v1"
25
+ _REQUEST_FIELDS = {"jsonrpc", "protocol", "id", "method", "params"}
26
+
27
+
28
+ class ProtocolError(Exception):
29
+ def __init__(self, code: str, message: str) -> None:
30
+ super().__init__(message)
31
+ self.code = code
32
+ self.message = message
33
+
34
+
35
+ def rebind_production_composition(home: CogniflowHome, snapshot: bytes, plan_digest: str, artifact_set_digest: str) -> None:
36
+ runtime = home.runtime(RuntimeId.PRODUCTION)
37
+ current = runtime.manifest.read_bytes()
38
+ text = snapshot.decode("utf-8")
39
+ rebound_text = re.sub(r'(?m)^plan_digest = "[^"]*"$', f'plan_digest = "{plan_digest}"', text, count=1)
40
+ rebound_text = re.sub(r'(?m)^artifact_set_digest = "[^"]*"$', f'artifact_set_digest = "{artifact_set_digest}"', rebound_text, count=1)
41
+ if rebound_text == text or rebound_text.count(plan_digest) != 1 or rebound_text.count(artifact_set_digest) != 1:
42
+ raise ValueError("production runtime manifest authority fields are invalid")
43
+ expected_b = RuntimeManifest.from_toml(rebound_text)
44
+ expected_b_bytes = expected_b.to_toml().encode("utf-8")
45
+ if current != snapshot and current != expected_b_bytes:
46
+ raise ValueError("production runtime manifest is mixed or foreign")
47
+ if current == expected_b_bytes:
48
+ return
49
+ temporary = runtime.manifest.with_suffix(".transition.tmp")
50
+ temporary.write_bytes(expected_b_bytes)
51
+ temporary.replace(runtime.manifest)
52
+
53
+
54
+ def _request_id(value: object) -> bool:
55
+ return (isinstance(value, int) and not isinstance(value, bool)) or (isinstance(value, str) and bool(value))
56
+
57
+
58
+ def _home(params: dict[str, object]) -> CogniflowHome:
59
+ value = params.get("cogniflow_home")
60
+ if value is None:
61
+ return CogniflowHome.default()
62
+ if not isinstance(value, str) or not value or "://" in value:
63
+ raise ProtocolError("INVALID_REQUEST", "cogniflow_home must be a local path string")
64
+ return CogniflowHome.at(value)
65
+
66
+
67
+ def _fields(params: object, *, required: set[str], optional: set[str]) -> dict[str, object]:
68
+ if not isinstance(params, dict) or any(not isinstance(key, str) for key in params):
69
+ raise ProtocolError("INVALID_REQUEST", "params must be an object with string fields")
70
+ if set(params) - required - optional or required - set(params):
71
+ raise ProtocolError("INVALID_REQUEST", "params fields do not match the operation schema")
72
+ return params
73
+
74
+
75
+ def _path(params: dict[str, object], name: str) -> Path:
76
+ value = params[name]
77
+ if not isinstance(value, str) or not value or "://" in value:
78
+ raise ProtocolError("INVALID_REQUEST", f"{name} must be a local path string")
79
+ return Path(value)
80
+
81
+
82
+ def _timeout(params: dict[str, object], name: str, default: float, *, allow_zero: bool = False) -> float:
83
+ value = params.get(name, default)
84
+ minimum = 0 if allow_zero else 0.001
85
+ if isinstance(value, bool) or not isinstance(value, (int, float)) or not minimum <= value <= 300:
86
+ raise ProtocolError("INVALID_REQUEST", f"{name} must be a number between {minimum} and 300")
87
+ return float(value)
88
+
89
+
90
+ def _manager(params: dict[str, object]) -> DevelopmentRuntime:
91
+ return DevelopmentRuntime(_home(params), lock_timeout=_timeout(params, "lock_timeout_seconds", 0.0, allow_zero=True))
92
+
93
+
94
+ def _resolve(params: object) -> dict[str, object]:
95
+ values = _fields(params, required={"runtime_id"}, optional={"cogniflow_home", "required_runtime_version", "required_semantic_revision"})
96
+ runtime_id = values["runtime_id"]
97
+ if runtime_id == "production":
98
+ try:
99
+ target = resolve_runtime_target(_home(values), RuntimeId.PRODUCTION)
100
+ except FileNotFoundError as error:
101
+ raise ProtocolError("PRODUCTION_RUNTIME_NOT_PROVISIONED", "production runtime has not been explicitly provisioned") from error
102
+ except ValueError as error:
103
+ raise ProtocolError("PRODUCTION_RUNTIME_INVALID", str(error)) from error
104
+ return target.payload()
105
+ if runtime_id != "development":
106
+ raise ProtocolError("INVALID_REQUEST", "runtime_id must be development or production")
107
+ for key in ("required_runtime_version", "required_semantic_revision"):
108
+ if key in values and (not isinstance(values[key], str) or not values[key]):
109
+ raise ProtocolError("INVALID_REQUEST", f"{key} must be a nonempty string")
110
+ target = resolve_runtime_target(_home(values), RuntimeId.DEVELOPMENT,
111
+ required_runtime_version=values.get("required_runtime_version"),
112
+ required_semantic_revision=values.get("required_semantic_revision"))
113
+ return target.payload()
114
+
115
+
116
+ def _production_preflight(params: object) -> dict[str, object]:
117
+ required = {"runtime_version", "release_version", "semantic_revision", "tool_versions",
118
+ "installation_root", "environment_root", "python_executable", "mcp_executable",
119
+ "instance_marker", "plan_digest", "artifact_set_digest", "native_mcp_distribution",
120
+ "native_mcp_version"}
121
+ values = _fields(params, required=required, optional={"cogniflow_home", "lock_timeout_seconds"})
122
+ tools = values["tool_versions"]
123
+ if not isinstance(tools, dict) or set(tools) != {"java", "fuseki"} or any(not isinstance(value, str) or not value for value in tools.values()):
124
+ raise ProtocolError("INVALID_REQUEST", "tool_versions must contain exactly java and fuseki strings")
125
+ for key in required - {"tool_versions"}:
126
+ if not isinstance(values[key], str) or not values[key]:
127
+ raise ProtocolError("INVALID_REQUEST", f"{key} must be a nonempty string")
128
+ home = _home(values)
129
+ from .locking import LifecycleLock
130
+ paths = home.runtime(RuntimeId.PRODUCTION)
131
+ with LifecycleLock(paths.lifecycle_lock, _timeout(values, "lock_timeout_seconds", 0.0, allow_zero=True)):
132
+ manifest = production_manifest(home, release_version=values["release_version"],
133
+ runtime_version=values["runtime_version"], semantic_revision=values["semantic_revision"],
134
+ tool_versions=tools, installation_root=_path(values, "installation_root"),
135
+ environment_root=_path(values, "environment_root"), python_executable=_path(values, "python_executable"),
136
+ mcp_executable=_path(values, "mcp_executable"), instance_marker=_path(values, "instance_marker"),
137
+ plan_digest=values["plan_digest"], artifact_set_digest=values["artifact_set_digest"],
138
+ native_mcp_distribution=values["native_mcp_distribution"], native_mcp_version=values["native_mcp_version"])
139
+ paths.ensure_directories()
140
+ content = manifest.to_toml().encode("utf-8")
141
+ if paths.manifest.exists():
142
+ if paths.manifest.read_bytes() != content:
143
+ raise ValueError("production manifest already contains a conflicting composition")
144
+ else:
145
+ manifest.write(paths.manifest)
146
+ return {"runtime_id": "production", "status": "preflight", "manifest": str(paths.manifest),
147
+ "semantic_revision": manifest.semantic_revision}
148
+
149
+
150
+ def _production_start(params: object) -> dict[str, object]:
151
+ values = _fields(params, required=set(), optional={"cogniflow_home", "lock_timeout_seconds", "timeout_seconds"})
152
+ return ProductionRuntime(_home(values), lock_timeout=_timeout(values, "lock_timeout_seconds", 0.0, allow_zero=True)).start(
153
+ timeout=_timeout(values, "timeout_seconds", 30.0))
154
+
155
+
156
+ def _production_status(params: object) -> dict[str, object]:
157
+ values = _fields(params, required=set(), optional={"cogniflow_home", "lock_timeout_seconds"})
158
+ return ProductionRuntime(_home(values), lock_timeout=_timeout(values, "lock_timeout_seconds", 0.0, allow_zero=True)).status()
159
+
160
+
161
+ def _production_stop(params: object) -> dict[str, object]:
162
+ values = _fields(params, required=set(), optional={"cogniflow_home", "lock_timeout_seconds", "timeout_seconds"})
163
+ return ProductionRuntime(_home(values), lock_timeout=_timeout(values, "lock_timeout_seconds", 0.0, allow_zero=True)).stop(
164
+ timeout=_timeout(values, "timeout_seconds", 5.0))
165
+
166
+
167
+ def _production_rebind(params: object) -> dict[str, object]:
168
+ values = _fields(params, required={"cogniflow_home", "snapshot_base64", "plan_digest", "artifact_set_digest"}, optional=set())
169
+ snapshot_value = values["snapshot_base64"]
170
+ if not isinstance(snapshot_value, str) or not snapshot_value:
171
+ raise ProtocolError("INVALID_REQUEST", "snapshot_base64 must be a nonempty canonical base64 string")
172
+ try:
173
+ snapshot = base64.b64decode(snapshot_value, validate=True)
174
+ except (ValueError, TypeError) as error:
175
+ raise ProtocolError("INVALID_REQUEST", "snapshot_base64 must be valid base64") from error
176
+ if base64.b64encode(snapshot).decode("ascii") != snapshot_value:
177
+ raise ProtocolError("INVALID_REQUEST", "snapshot_base64 must be canonical base64")
178
+ for name in ("plan_digest", "artifact_set_digest"):
179
+ value = values[name]
180
+ if not isinstance(value, str) or not re.fullmatch(r"sha256:[0-9a-f]{64}", value):
181
+ raise ProtocolError("INVALID_REQUEST", f"{name} must be a sha256 digest")
182
+ rebind_production_composition(_home(values), snapshot, values["plan_digest"], values["artifact_set_digest"])
183
+ return {"runtime_id": "production", "status": "rebound"}
184
+
185
+
186
+ def _production_semantics_register(params: object) -> dict[str, object]:
187
+ values = _fields(params, required={"documents"}, optional={"cogniflow_home", "lock_timeout_seconds"})
188
+ return register_semantics(_home(values), values["documents"])
189
+
190
+
191
+ def _production_semantics_restore(params: object) -> dict[str, object]:
192
+ values = _fields(params, required={"receipt"}, optional={"cogniflow_home", "lock_timeout_seconds"})
193
+ return restore_semantics(_home(values), values["receipt"])
194
+
195
+
196
+ def _production_semantics_recover_stopped(params: object) -> dict[str, object]:
197
+ values = _fields(params, required={"receipt"}, optional={"cogniflow_home", "timeout_seconds"})
198
+ return recover_stopped_semantics(_home(values), values["receipt"], timeout=_timeout(values, "timeout_seconds", 30.0))
199
+
200
+
201
+ def _production_semantics_transition(params: object) -> dict[str, object]:
202
+ values = _fields(params, required={"before", "after"}, optional={"cogniflow_home", "lock_timeout_seconds"})
203
+ return transition_semantics(_home(values), values["before"], values["after"])
204
+
205
+
206
+ def _production_semantics_uninstall(params: object) -> dict[str, object]:
207
+ values = _fields(params, required={"documents"}, optional={"cogniflow_home", "lock_timeout_seconds"})
208
+ return uninstall_semantics(_home(values), values["documents"])
209
+
210
+
211
+ def _production_semantics_status(params: object) -> dict[str, object]:
212
+ values = _fields(params, required={"documents"}, optional={"cogniflow_home", "lock_timeout_seconds"})
213
+ return status_semantics(_home(values), values["documents"])
214
+
215
+
216
+ def _production_teardown_plan(params: object) -> dict[str, object]:
217
+ values = _fields(params, required=set(), optional={"cogniflow_home"})
218
+ return plan_teardown(_home(values))
219
+
220
+
221
+ def _production_teardown_prepare(params: object) -> dict[str, object]:
222
+ values = _fields(params, required={"transaction_id", "nonce", "authority", "preview_digest", "documents"}, optional={"cogniflow_home"})
223
+ return prepare_teardown(_home(values), transaction_id=values["transaction_id"], nonce=values["nonce"], authority=values["authority"], preview_digest=values["preview_digest"], documents=values["documents"])
224
+
225
+
226
+ def _production_teardown_attest(params: object) -> dict[str, object]:
227
+ values = _fields(params, required={"transaction"}, optional={"cogniflow_home"})
228
+ return attest_teardown(_home(values), values["transaction"])
229
+
230
+
231
+ def _production_teardown_stop(params: object) -> dict[str, object]:
232
+ values = _fields(params, required={"transaction"}, optional={"cogniflow_home", "timeout_seconds"})
233
+ return stop_teardown(_home(values), values["transaction"], timeout=_timeout(values, "timeout_seconds", 30.0))
234
+
235
+
236
+ def _production_teardown_cleanup(params: object) -> dict[str, object]:
237
+ values = _fields(params, required={"transaction"}, optional={"cogniflow_home"})
238
+ return cleanup_teardown(_home(values), values["transaction"])
239
+
240
+
241
+ def _production_teardown_finalize(params: object) -> dict[str, object]:
242
+ values = _fields(params, required={"transaction"}, optional={"cogniflow_home"})
243
+ return finalize_teardown(_home(values), values["transaction"])
244
+
245
+
246
+ def _production_teardown_recover(params: object) -> dict[str, object]:
247
+ values = _fields(params, required={"transaction"}, optional={"cogniflow_home", "timeout_seconds"})
248
+ return recover_teardown(_home(values), values["transaction"], timeout=_timeout(values, "timeout_seconds", 30.0))
249
+
250
+
251
+ def _prepare(params: object) -> dict[str, object]:
252
+ values = _fields(params, required={"source_root", "semantic_seed"},
253
+ optional={"cogniflow_home", "lock_timeout_seconds"})
254
+ return _manager(values).prepare(_path(values, "source_root"), _path(values, "semantic_seed"))
255
+
256
+
257
+ def _start(params: object) -> dict[str, object]:
258
+ values = _fields(params, required={"source_root", "semantic_seed"},
259
+ optional={"cogniflow_home", "lock_timeout_seconds", "timeout_seconds"})
260
+ return _manager(values).start(_path(values, "source_root"), _path(values, "semantic_seed"),
261
+ timeout=_timeout(values, "timeout_seconds", 30.0))
262
+
263
+
264
+ def _status(params: object) -> dict[str, object]:
265
+ values = _fields(params, required=set(), optional={"cogniflow_home", "lock_timeout_seconds"})
266
+ return _manager(values).status()
267
+
268
+
269
+ def _stop(params: object) -> dict[str, object]:
270
+ values = _fields(params, required=set(), optional={"cogniflow_home", "lock_timeout_seconds", "timeout_seconds"})
271
+ return _manager(values).stop(timeout=_timeout(values, "timeout_seconds", 5.0))
272
+
273
+
274
+ def _managed_tools(params: object) -> dict[str, object]:
275
+ values = _fields(params, required={"schema", "tools"}, optional={"cogniflow_home", "lock_timeout_seconds"})
276
+ if values["schema"] != MANAGED_REQUEST_SCHEMA:
277
+ raise ProtocolError("SCHEMA_UNSUPPORTED", "unsupported managed-tools request schema")
278
+ tools = values["tools"]
279
+ if not isinstance(tools, list) or len(tools) != 2:
280
+ raise ProtocolError("INVALID_REQUEST", "tools must contain exactly java and fuseki")
281
+ versions: dict[str, str] = {}
282
+ for item in tools:
283
+ if not isinstance(item, dict) or set(item) != {"name", "version"} or item.get("name") in versions:
284
+ raise ProtocolError("INVALID_REQUEST", "tool requests are strict name/version objects")
285
+ if item["name"] not in {"java", "fuseki"} or not isinstance(item["version"], str) or not item["version"]:
286
+ raise ProtocolError("INVALID_REQUEST", "invalid managed tool request")
287
+ versions[item["name"]] = item["version"]
288
+ if set(versions) != {"java", "fuseki"}:
289
+ raise ProtocolError("INVALID_REQUEST", "java and fuseki are both required")
290
+ try:
291
+ return ManagedTools(_home(values), lock_timeout=_timeout(values, "lock_timeout_seconds", 0.0, allow_zero=True)).provision(versions["java"], versions["fuseki"])
292
+ except LifecycleLockedError as error:
293
+ raise ProtocolError("MANAGED_TOOLS_LOCKED", "managed-tool provisioning is locked") from error
294
+ except ManagedToolsError as error:
295
+ raise ProtocolError(error.code, str(error)) from error
296
+
297
+
298
+ _OPERATIONS: dict[str, Callable[[object], dict[str, object]]] = {
299
+ "runtime/resolve-target": _resolve,
300
+ "production/preflight": _production_preflight,
301
+ "production/start": _production_start,
302
+ "production/status": _production_status,
303
+ "production/stop": _production_stop,
304
+ "production/composition/rebind": _production_rebind,
305
+ "production/semantics/register": _production_semantics_register,
306
+ "production/semantics/restore": _production_semantics_restore,
307
+ "production/semantics/recover-stopped": _production_semantics_recover_stopped,
308
+ "production/semantics/transition": _production_semantics_transition,
309
+ "production/semantics/status": _production_semantics_status,
310
+ "production/semantics/uninstall": _production_semantics_uninstall,
311
+ "production/teardown/plan": _production_teardown_plan,
312
+ "production/teardown/prepare": _production_teardown_prepare,
313
+ "production/teardown/attest": _production_teardown_attest,
314
+ "production/teardown/stop": _production_teardown_stop,
315
+ "production/teardown/cleanup": _production_teardown_cleanup,
316
+ "production/teardown/finalize": _production_teardown_finalize,
317
+ "production/teardown/recover": _production_teardown_recover,
318
+ "development/prepare": _prepare,
319
+ "development/start": _start,
320
+ "development/status": _status,
321
+ "development/stop": _stop,
322
+ "managed-tools/provision": _managed_tools,
323
+ }
324
+
325
+
326
+ def handle(payload: object) -> dict[str, object]:
327
+ request_id: object = None
328
+ method = "unknown"
329
+ try:
330
+ if not isinstance(payload, dict) or set(payload) != _REQUEST_FIELDS:
331
+ raise ProtocolError("INVALID_REQUEST", "request fields do not match the protocol")
332
+ candidate_id = payload.get("id")
333
+ if not _request_id(candidate_id) or payload.get("jsonrpc") != JSONRPC:
334
+ raise ProtocolError("INVALID_REQUEST", "invalid jsonrpc or request id")
335
+ request_id = candidate_id
336
+ if payload.get("protocol") != PROTOCOL:
337
+ raise ProtocolError("PROTOCOL_VERSION_UNSUPPORTED", "unsupported bootstrap protocol version")
338
+ method = payload.get("method")
339
+ if not isinstance(method, str) or not method:
340
+ raise ProtocolError("INVALID_REQUEST", "method must be a nonempty string")
341
+ operation = _OPERATIONS.get(method)
342
+ if operation is None:
343
+ raise ProtocolError("UNKNOWN_OPERATION", "unknown bootstrap operation")
344
+ result = operation(payload.get("params"))
345
+ return {"jsonrpc": JSONRPC, "protocol": PROTOCOL, "id": request_id, "result": result}
346
+ except LifecycleLockedError:
347
+ error = ProtocolError("DEVELOPMENT_LIFECYCLE_LOCKED", "development lifecycle is locked")
348
+ except ProtocolError as caught:
349
+ error = caught
350
+ except (ValueError, TypeError, FileNotFoundError) as caught:
351
+ error = ProtocolError("INVALID_REQUEST", str(caught))
352
+ except Exception as caught:
353
+ # Keep provider failures useful without returning URLs, environments, or
354
+ # an unbounded traceback through the JSON protocol.
355
+ message = f"operation={method} exception={type(caught).__name__}: {caught}"
356
+ error = ProtocolError("INTERNAL_ERROR", message[:1024])
357
+ return {"jsonrpc": JSONRPC, "protocol": PROTOCOL, "id": request_id,
358
+ "error": {"code": error.code, "message": error.message}}
359
+
360
+
361
+ def main() -> int:
362
+ for line in sys.stdin:
363
+ try:
364
+ payload = json.loads(line)
365
+ except json.JSONDecodeError:
366
+ response = {"jsonrpc": JSONRPC, "protocol": PROTOCOL, "id": None,
367
+ "error": {"code": "INVALID_REQUEST", "message": "request must be valid JSON"}}
368
+ else:
369
+ response = handle(payload)
370
+ sys.stdout.write(json.dumps(response, sort_keys=True, separators=(",", ":")) + "\n")
371
+ sys.stdout.flush()
372
+ return 0
373
+
374
+
375
+ if __name__ == "__main__":
376
+ raise SystemExit(main())
cf_runtime/domain.py ADDED
@@ -0,0 +1,25 @@
1
+ """Closed vocabulary used by the runtime domain."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class RuntimeId(str, Enum):
7
+ DEVELOPMENT = "development"
8
+ PRODUCTION = "production"
9
+
10
+
11
+ class EnvironmentKind(Enum):
12
+ """Deployment semantics, intentionally distinct from runtime identity."""
13
+
14
+ DEVELOPMENT = "development"
15
+ PRODUCTION = "production"
16
+
17
+
18
+ class SourceKind(str, Enum):
19
+ WORKING_TREE = "working-tree"
20
+ RELEASE = "release"
21
+
22
+
23
+ class McpTransport(str, Enum):
24
+ STDIO = "stdio"
25
+ UNAVAILABLE = "unavailable"
@@ -0,0 +1,57 @@
1
+ """Build the production semantic seed from installed entry points only."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import hashlib
7
+ import importlib.metadata
8
+ import os
9
+ from pathlib import Path
10
+
11
+
12
+ def build(output: Path) -> str:
13
+ root = Path(sys_prefix := os.path.abspath(os.sys.prefix))
14
+ records: list[tuple[str, str, Path]] = []
15
+ entries = importlib.metadata.entry_points().select(group="cogniflow.semantic_sources")
16
+ for entry in entries:
17
+ distribution = (entry.dist.metadata.get("Name") if entry.dist else "") or ""
18
+ value = entry.load()()
19
+ if not isinstance(value, (tuple, list)) or any(not isinstance(item, Path) for item in value):
20
+ raise ValueError(f"semantic source {entry.name} returned a non-Path sequence")
21
+ for path in value:
22
+ resolved = path.resolve(strict=True)
23
+ if not resolved.is_file() or resolved.is_symlink():
24
+ raise ValueError(f"semantic source is not a regular file: {path}")
25
+ try:
26
+ resolved.relative_to(root)
27
+ except ValueError as error:
28
+ raise ValueError(f"semantic source is outside the target environment: {path}") from error
29
+ records.append((distribution.casefold(), entry.name.casefold(), resolved))
30
+ records.sort(key=lambda item: (item[0], item[1], item[2].as_posix().casefold()))
31
+ chunks: list[bytes] = []
32
+ seen: set[Path] = set()
33
+ for distribution, name, path in records:
34
+ if path in seen:
35
+ raise ValueError(f"duplicate semantic source: {path}")
36
+ seen.add(path)
37
+ chunks.append(f"# source: {distribution}/{name}/{path.name}\n".encode("utf-8"))
38
+ data = path.read_bytes()
39
+ chunks.append(data.rstrip(b"\r\n") + b"\n")
40
+ data = b"".join(chunks)
41
+ output.parent.mkdir(parents=True, exist_ok=True)
42
+ temporary = output.with_name(f".{output.name}.tmp")
43
+ temporary.write_bytes(data)
44
+ os.replace(temporary, output)
45
+ return hashlib.sha256(data).hexdigest()
46
+
47
+
48
+ def main() -> int:
49
+ parser = argparse.ArgumentParser()
50
+ parser.add_argument("--output", required=True)
51
+ args = parser.parse_args()
52
+ print(build(Path(args.output)))
53
+ return 0
54
+
55
+
56
+ if __name__ == "__main__":
57
+ raise SystemExit(main())