clm-kernel 0.0.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.
Files changed (333) hide show
  1. clm/__init__.py +230 -0
  2. clm/__main__.py +25 -0
  3. clm/cross_cutting/__init__.py +50 -0
  4. clm/cross_cutting/_test_runner.py +36 -0
  5. clm/cross_cutting/async_utils.py +25 -0
  6. clm/cross_cutting/cel_builder.py +123 -0
  7. clm/cross_cutting/cel_converter.py +697 -0
  8. clm/cross_cutting/cel_engine.py +252 -0
  9. clm/cross_cutting/cel_ops.py +72 -0
  10. clm/cross_cutting/cel_ops_db.py +157 -0
  11. clm/cross_cutting/cel_ops_files.py +99 -0
  12. clm/cross_cutting/cel_ops_state.py +71 -0
  13. clm/cross_cutting/cel_ops_strings.py +64 -0
  14. clm/cross_cutting/cel_resolver.py +63 -0
  15. clm/cross_cutting/cel_slices.py +56 -0
  16. clm/cross_cutting/cel_store.py +330 -0
  17. clm/cross_cutting/clm_logger.py +140 -0
  18. clm/cross_cutting/config/__init__.py +155 -0
  19. clm/cross_cutting/config/config_constants.py +392 -0
  20. clm/cross_cutting/config/env_parameters.py +90 -0
  21. clm/cross_cutting/config/logging.py +378 -0
  22. clm/cross_cutting/config/settings.py +504 -0
  23. clm/cross_cutting/context.py +5 -0
  24. clm/cross_cutting/domain_models.py +55 -0
  25. clm/cross_cutting/domain_types.py +61 -0
  26. clm/cross_cutting/effects.py +67 -0
  27. clm/cross_cutting/errors.py +153 -0
  28. clm/cross_cutting/governance.py +331 -0
  29. clm/cross_cutting/guards.py +41 -0
  30. clm/cross_cutting/mcard.py +321 -0
  31. clm/cross_cutting/native.py +185 -0
  32. clm/cross_cutting/observability.py +289 -0
  33. clm/cross_cutting/pcard.py +434 -0
  34. clm/cross_cutting/registry.py +71 -0
  35. clm/cross_cutting/resources.py +84 -0
  36. clm/cross_cutting/secrets.py +44 -0
  37. clm/cross_cutting/subprocess_utils.py +118 -0
  38. clm/cross_cutting/telemetry.py +164 -0
  39. clm/cross_cutting/testing/__init__.py +8 -0
  40. clm/cross_cutting/testing/comparator.py +187 -0
  41. clm/cross_cutting/testing/datasets.py +87 -0
  42. clm/cross_cutting/timeutil.py +20 -0
  43. clm/cross_cutting/types/new_type_check.py +0 -0
  44. clm/cross_cutting/utils/__init__.py +1 -0
  45. clm/cross_cutting/utils/url_safety.py +50 -0
  46. clm/cross_cutting/vcard.py +560 -0
  47. clm/cross_cutting/writer.py +118 -0
  48. clm/layer0/README.md +50 -0
  49. clm/layer0/__init__.py +223 -0
  50. clm/layer0/algebra.py +60 -0
  51. clm/layer0/algebra_baldwin.py +133 -0
  52. clm/layer0/algebra_baldwin_generators.py +36 -0
  53. clm/layer0/algebra_equivalence.py +262 -0
  54. clm/layer0/algebra_ingest.py +306 -0
  55. clm/layer0/algebra_manifest_io.py +156 -0
  56. clm/layer0/assembler.py +481 -0
  57. clm/layer0/cel/__init__.py +23 -0
  58. clm/layer0/cel_eval.py +491 -0
  59. clm/layer0/codec.py +106 -0
  60. clm/layer0/context.py +122 -0
  61. clm/layer0/db.py +160 -0
  62. clm/layer0/exceptions.py +73 -0
  63. clm/layer0/fibration.py +106 -0
  64. clm/layer0/gates.py +50 -0
  65. clm/layer0/hash.py +80 -0
  66. clm/layer0/loader.py +826 -0
  67. clm/layer0/math_utils.py +163 -0
  68. clm/layer0/mcard.py +96 -0
  69. clm/layer0/model/__init__.py +0 -0
  70. clm/layer0/model/action.py +223 -0
  71. clm/layer0/model/card.py +280 -0
  72. clm/layer0/model/card_triad.py +427 -0
  73. clm/layer0/model/compatibility.py +60 -0
  74. clm/layer0/model/dictionary.py +46 -0
  75. clm/layer0/model/dots.py +331 -0
  76. clm/layer0/model/event_producer.py +88 -0
  77. clm/layer0/model/g_time.py +89 -0
  78. clm/layer0/model/handle.py +163 -0
  79. clm/layer0/model/hash/__init__.py +6 -0
  80. clm/layer0/model/hash/algorithms/__init__.py +3 -0
  81. clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
  82. clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
  83. clm/layer0/model/hash/constants.py +53 -0
  84. clm/layer0/model/hash/enums.py +60 -0
  85. clm/layer0/model/hash/validator.py +307 -0
  86. clm/layer0/model/interpreter.py +275 -0
  87. clm/layer0/model/pagination.py +45 -0
  88. clm/layer0/model/pcard.py +716 -0
  89. clm/layer0/model/schema.py +44 -0
  90. clm/layer0/model/utils/__init__.py +1 -0
  91. clm/layer0/model/utils/content_analyzer.py +152 -0
  92. clm/layer0/model/validators/__init__.py +1 -0
  93. clm/layer0/model/validators/base_validator.py +44 -0
  94. clm/layer0/model/validators/binary_validator.py +66 -0
  95. clm/layer0/model/validators/text_validator.py +82 -0
  96. clm/layer0/model/validators/validation_registry.py +49 -0
  97. clm/layer0/model/vcard.py +823 -0
  98. clm/layer0/model/vcard_ext/__init__.py +39 -0
  99. clm/layer0/model/vcard_ext/core.py +60 -0
  100. clm/layer0/model/vcard_ext/network.py +23 -0
  101. clm/layer0/model/vcard_ext/observability.py +63 -0
  102. clm/layer0/model/vcard_ext/storage.py +60 -0
  103. clm/layer0/model/vcard_ext/vendors.py +211 -0
  104. clm/layer0/model/vcard_sandwich.py +119 -0
  105. clm/layer0/model/vcard_vocabulary.py +463 -0
  106. clm/layer0/model/workflow.py +274 -0
  107. clm/layer0/narrative.py +431 -0
  108. clm/layer0/ontology/collection.py +125 -0
  109. clm/layer0/parser.py +429 -0
  110. clm/layer0/relations.py +73 -0
  111. clm/layer0/rule_evaluator.py +251 -0
  112. clm/layer0/schema/__init__.py +38 -0
  113. clm/layer0/schema/ddl.py +97 -0
  114. clm/layer0/templates/abstract.yaml +99 -0
  115. clm/layer0/templates/balanced.yaml +253 -0
  116. clm/layer0/templates/concrete.yaml +172 -0
  117. clm/layer0/type_registry.py +223 -0
  118. clm/layer0/types.py +204 -0
  119. clm/layer0/utils.py +886 -0
  120. clm/layer0/verifier_core.py +262 -0
  121. clm/layer1/__init__.py +31 -0
  122. clm/layer1/action_dispatcher.py +275 -0
  123. clm/layer1/adapter_registry.py +233 -0
  124. clm/layer1/algebra_baldwin_generators.py +192 -0
  125. clm/layer1/arrow_compiler.py +525 -0
  126. clm/layer1/batch_processor.py +152 -0
  127. clm/layer1/cel/__init__.py +27 -0
  128. clm/layer1/cel/builder.py +173 -0
  129. clm/layer1/engine.py +759 -0
  130. clm/layer1/engine_async.py +89 -0
  131. clm/layer1/eval_callback.py +49 -0
  132. clm/layer1/gate_composer.py +229 -0
  133. clm/layer1/hoare_sandwich.py +298 -0
  134. clm/layer1/identity_guard.py +348 -0
  135. clm/layer1/matrix.py +138 -0
  136. clm/layer1/neural_runtime.py +221 -0
  137. clm/layer1/operations/__init__.py +123 -0
  138. clm/layer1/operations/augment.py +156 -0
  139. clm/layer1/operations/base.py +109 -0
  140. clm/layer1/operations/builtins.py +338 -0
  141. clm/layer1/operations/dispatch.py +144 -0
  142. clm/layer1/operations/exclude.py +107 -0
  143. clm/layer1/operations/handle.py +197 -0
  144. clm/layer1/operations/identity.py +139 -0
  145. clm/layer1/operations/invert.py +66 -0
  146. clm/layer1/operations/loader.py +116 -0
  147. clm/layer1/operations/manipulators/__init__.py +23 -0
  148. clm/layer1/operations/manipulators/document.py +211 -0
  149. clm/layer1/operations/manipulators/media.py +134 -0
  150. clm/layer1/operations/manipulators/structured.py +159 -0
  151. clm/layer1/operations/manipulators/tabular.py +334 -0
  152. clm/layer1/operations/port.py +65 -0
  153. clm/layer1/operations/services.py +529 -0
  154. clm/layer1/operations/split.py +117 -0
  155. clm/layer1/operations/substitute.py +75 -0
  156. clm/layer1/petri.py +1052 -0
  157. clm/layer1/pocketflow_orchestrator.py +408 -0
  158. clm/layer1/pocketflow_scheduler.py +519 -0
  159. clm/layer1/protocols.py +197 -0
  160. clm/layer1/runtime_adapter.py +718 -0
  161. clm/layer1/runtimes/__init__.py +71 -0
  162. clm/layer1/runtimes/_generated_assertions.py +125 -0
  163. clm/layer1/runtimes/_generated_types.py +42 -0
  164. clm/layer1/runtimes/base.py +265 -0
  165. clm/layer1/runtimes/binary.py +101 -0
  166. clm/layer1/runtimes/factory.py +203 -0
  167. clm/layer1/runtimes/javascript.py +321 -0
  168. clm/layer1/runtimes/javascript_runtime.js +33 -0
  169. clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
  170. clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
  171. clm/layer1/runtimes/lambda_calc.py +126 -0
  172. clm/layer1/runtimes/python.py +288 -0
  173. clm/layer1/runtimes/python_runtime.py +41 -0
  174. clm/layer1/runtimes/script.py +114 -0
  175. clm/layer1/sandbox.py +334 -0
  176. clm/layer1/savepoint_guard.py +136 -0
  177. clm/layer1/sparse_net.py +122 -0
  178. clm/layer1/spec_tester.py +165 -0
  179. clm/layer1/store.py +295 -0
  180. clm/layer1/test_runner.py +498 -0
  181. clm/layer1/type_inspector.py +166 -0
  182. clm/layer1/verifier.py +772 -0
  183. clm/layer1/vm.py +91 -0
  184. clm/layer2/__init__.py +78 -0
  185. clm/layer2/card_collection.py +678 -0
  186. clm/layer2/classifier.py +479 -0
  187. clm/layer2/engine/__init__.py +1 -0
  188. clm/layer2/engine/abstract_sql_engine.py +320 -0
  189. clm/layer2/engine/base.py +193 -0
  190. clm/layer2/engine/duckdb_engine.py +576 -0
  191. clm/layer2/engine/sqlite_engine.py +518 -0
  192. clm/layer2/fiber/__init__.py +31 -0
  193. clm/layer2/fiber/context.py +89 -0
  194. clm/layer2/fiber/disposable.py +163 -0
  195. clm/layer2/fiber/fiber.py +125 -0
  196. clm/layer2/fiber/hoare.py +191 -0
  197. clm/layer2/file_io.py +376 -0
  198. clm/layer2/file_registrar.py +77 -0
  199. clm/layer2/ingest.py +202 -0
  200. clm/layer2/lineage.py +322 -0
  201. clm/layer2/mcard_fs.py +262 -0
  202. clm/layer2/merkle.py +11 -0
  203. clm/layer2/mime.py +244 -0
  204. clm/layer2/mime_detector.py +245 -0
  205. clm/layer2/private_collection.py +118 -0
  206. clm/layer2/shared_store.py +11 -0
  207. clm/layer2/storage/__init__.py +190 -0
  208. clm/layer2/storage/db_bitemporal.py +141 -0
  209. clm/layer2/storage/db_driver.py +331 -0
  210. clm/layer2/storage/db_hyperlinks.py +214 -0
  211. clm/layer2/storage/db_pool.py +139 -0
  212. clm/layer2/storage/db_repository.py +229 -0
  213. clm/layer2/storage/savepoint.py +78 -0
  214. clm/layer2/storage/sqlite_wal.py +74 -0
  215. clm/layer2/tridb.py +245 -0
  216. clm/layer2/vcard_receipt.py +71 -0
  217. clm/layer2/vfs.py +17 -0
  218. clm/layer3/__init__.py +141 -0
  219. clm/layer3/agency/__init__.py +19 -0
  220. clm/layer3/agency/config.py +220 -0
  221. clm/layer3/agency/providers/__init__.py +15 -0
  222. clm/layer3/agency/providers/base.py +91 -0
  223. clm/layer3/agency/providers/mlc_llm.py +169 -0
  224. clm/layer3/agency/providers/ollama.py +203 -0
  225. clm/layer3/agency/router.py +71 -0
  226. clm/layer3/agency/runtime.py +524 -0
  227. clm/layer3/gateway.py +353 -0
  228. clm/layer3/open_interpreter_adapter.py +159 -0
  229. clm/layer3/rag/__init__.py +70 -0
  230. clm/layer3/rag/cli.py +228 -0
  231. clm/layer3/rag/config.py +153 -0
  232. clm/layer3/rag/embeddings/__init__.py +16 -0
  233. clm/layer3/rag/embeddings/base.py +79 -0
  234. clm/layer3/rag/embeddings/ollama.py +211 -0
  235. clm/layer3/rag/embeddings/vision.py +290 -0
  236. clm/layer3/rag/engine.py +276 -0
  237. clm/layer3/rag/graph/__init__.py +22 -0
  238. clm/layer3/rag/graph/community.py +198 -0
  239. clm/layer3/rag/graph/engine.py +433 -0
  240. clm/layer3/rag/graph/extractor.py +255 -0
  241. clm/layer3/rag/graph/schema.py +115 -0
  242. clm/layer3/rag/graph/store.py +641 -0
  243. clm/layer3/rag/indexer.py +333 -0
  244. clm/layer3/rag/llm_providers.json +52 -0
  245. clm/layer3/rag/semantic_versioning.py +313 -0
  246. clm/layer3/rag/vector/__init__.py +28 -0
  247. clm/layer3/rag/vector/handle_vector_store.py +749 -0
  248. clm/layer3/rag/vector/schema.py +151 -0
  249. clm/layer3/rag/vector/store.py +632 -0
  250. clm/layer3/reticulum/__init__.py +55 -0
  251. clm/layer3/reticulum/bridge.py +74 -0
  252. clm/layer3/reticulum/daemon.py +88 -0
  253. clm/layer3/reticulum/discovery.py +164 -0
  254. clm/layer3/reticulum/identity.py +107 -0
  255. clm/layer3/reticulum/media.py +148 -0
  256. clm/layer3/reticulum/transport.py +133 -0
  257. clm/layer3/satori/__init__.py +209 -0
  258. clm/layer3/satori/alpha_conversion.py +168 -0
  259. clm/layer3/satori/beta_reduction.py +359 -0
  260. clm/layer3/satori/continuation.py +38 -0
  261. clm/layer3/satori/eta_conversion.py +205 -0
  262. clm/layer3/satori/free_variables.py +163 -0
  263. clm/layer3/satori/io_effects.py +370 -0
  264. clm/layer3/satori/lambda_runtime.py +726 -0
  265. clm/layer3/satori/lambda_term.py +230 -0
  266. clm/layer3/satori/sheaf_audit.py +261 -0
  267. clm/layer3/satori/speech_act.py +279 -0
  268. clm/layer4/README.md +9 -0
  269. clm/layer4/__init__.py +67 -0
  270. clm/layer4/_sovereign_executor.py +580 -0
  271. clm/layer4/action_commands.py +719 -0
  272. clm/layer4/api.py +236 -0
  273. clm/layer4/bootstrap/__init__.py +13 -0
  274. clm/layer4/bootstrap/bootstrapper.py +118 -0
  275. clm/layer4/bootstrap/cleanup.py +44 -0
  276. clm/layer4/bootstrap/clm_hooks.py +49 -0
  277. clm/layer4/bootstrap/genesis.py +77 -0
  278. clm/layer4/bootstrap/injection.py +125 -0
  279. clm/layer4/cli.py +549 -0
  280. clm/layer4/collection_manager.py +553 -0
  281. clm/layer4/commands/__init__.py +81 -0
  282. clm/layer4/commands/action_cmd.py +42 -0
  283. clm/layer4/commands/check_cmd.py +82 -0
  284. clm/layer4/commands/envelope.py +73 -0
  285. clm/layer4/commands/evaluate_cmd.py +224 -0
  286. clm/layer4/commands/mcard_cmd.py +24 -0
  287. clm/layer4/commands/petri_cmd.py +92 -0
  288. clm/layer4/commands/tridb_cmd.py +319 -0
  289. clm/layer4/commands/version_cmd.py +27 -0
  290. clm/layer4/diff_commands.py +167 -0
  291. clm/layer4/eoa_sponsor.py +232 -0
  292. clm/layer4/events.py +69 -0
  293. clm/layer4/flux_gateway.py +133 -0
  294. clm/layer4/gateway.py +91 -0
  295. clm/layer4/loader.py +307 -0
  296. clm/layer4/mcard_commands.py +166 -0
  297. clm/layer4/membrane.py +273 -0
  298. clm/layer4/navigation.py +50 -0
  299. clm/layer4/protocol/protocol_entry_python.py +108 -0
  300. clm/layer4/protocol/python_sync.py +126 -0
  301. clm/layer4/runner.py +150 -0
  302. clm/layer4/satori.py +262 -0
  303. clm/layer4/server/python_sync_client.py +150 -0
  304. clm/layer4/server/python_sync_server.py +139 -0
  305. clm/layer4/server/service_api.py +315 -0
  306. clm/layer4/server/start_servers.py +107 -0
  307. clm/layer4/server/stop_servers.py +24 -0
  308. clm/layer4/simulated_optimization_fix.py +0 -0
  309. clm/layer4/storage.py +463 -0
  310. clm/layer4/tridb_admin.py +268 -0
  311. clm/layer4/websocket/test_ws_client.py +104 -0
  312. clm/layer4/websocket/test_ws_server.py +138 -0
  313. clm/layer4/websocket/ws_server_local.py +160 -0
  314. clm/layer5/__init__.py +51 -0
  315. clm/layer5/async_batch_writer.py +133 -0
  316. clm/layer5/learning.py +276 -0
  317. clm/layer5/telemetry_hook.py +107 -0
  318. clm/layer5/type_lattice.py +238 -0
  319. clm/py.typed +0 -0
  320. clm/schemas/__init__.py +652 -0
  321. clm/schemas/abstract_face_schema.yaml +77 -0
  322. clm/schemas/cel_schema.yaml +416 -0
  323. clm/schemas/lifecycle/__init__.py +45 -0
  324. clm/schemas/lifecycle/models.py +123 -0
  325. clm/schemas/lifecycle/service.py +364 -0
  326. clm/schemas/mcard_schema.sql +192 -0
  327. clm/schemas/mcard_vector_schema.sql +283 -0
  328. clm/schemas/mlp-context-v1.json +91 -0
  329. clm_kernel-0.0.0.dist-info/METADATA +121 -0
  330. clm_kernel-0.0.0.dist-info/RECORD +333 -0
  331. clm_kernel-0.0.0.dist-info/WHEEL +4 -0
  332. clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
  333. clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
clm/layer4/cli.py ADDED
@@ -0,0 +1,549 @@
1
+ """CLM CLI — Canonical Layer 4 Human Interaction Surface.
2
+
3
+ This module is the single canonical entry point for all CLI interactions
4
+ with the CLM kernel. It unifies:
5
+ - The sovereign executor pipeline (evaluate, memorize-mcard, init-tridb, etc.)
6
+ - The argparse-based front-end (run, status, list, flow, launch)
7
+
8
+ Usage:
9
+ clm <clm_file> # sovereign evaluate
10
+ clm evaluate <clm_file> [extra_args] # sovereign evaluate (explicit)
11
+ python -m clm run <file.yaml> # argparse front-end
12
+ python -m clm status --verbose # runtime status
13
+ python -m clm launch # sovereign node
14
+
15
+ Sprint 382: Consolidated from clm.layer3.cli → clm.layer4.cli.
16
+ """
17
+
18
+ import argparse
19
+ import asyncio
20
+ import json
21
+ import logging
22
+ import sys
23
+ from pathlib import Path
24
+ from typing import Any
25
+
26
+ import yaml
27
+
28
+ from clm.layer1.engine import PTREngine
29
+ from clm.layer1.engine_async import AsyncPTREngine
30
+ from clm.layer1.runtimes import RuntimeFactory
31
+
32
+ # ---------------------------------------------------------------------------
33
+ # Sprint 382: Re-export the sovereign executor pipeline from Layer 4.
34
+ # The full implementation lives in _sovereign_executor.py (moved from
35
+ # layer3/cli.py). These two symbols are the public contract consumed by
36
+ # clm/__init__.py, clm/__main__.py, layer3/__init__.py and pyproject.toml.
37
+ # ---------------------------------------------------------------------------
38
+ from clm.layer4._sovereign_executor import ( # noqa: F401, E402
39
+ evaluate_cmd,
40
+ )
41
+ from clm.layer4.runner import CLMRunner
42
+
43
+ # ─────────────────────────────────────────────────────────────────────────────
44
+ # Setup and Utilities
45
+ # ─────────────────────────────────────────────────────────────────────────────
46
+
47
+
48
+ def setup_logging(level: int = logging.INFO) -> None:
49
+ """Configure basic logging for CLI output."""
50
+ logging.basicConfig(
51
+ level=level, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
52
+ )
53
+
54
+
55
+ def parse_context(ctx_str: str) -> dict[str, Any]:
56
+ """Parse JSON context string into dictionary."""
57
+ if not ctx_str or ctx_str == "{}":
58
+ return {}
59
+ try:
60
+ return json.loads(ctx_str)
61
+ except json.JSONDecodeError as e:
62
+ print(f"❌ Error parsing context JSON: {e}", file=sys.stderr)
63
+ sys.exit(1)
64
+
65
+
66
+ # ─────────────────────────────────────────────────────────────────────────────
67
+ # Commands
68
+ # ─────────────────────────────────────────────────────────────────────────────
69
+
70
+
71
+ def run_command(args: argparse.Namespace) -> None:
72
+ """Execute a CLM/PCard file or all CLMs in a directory."""
73
+ file_path = Path(args.file)
74
+
75
+ if file_path.is_dir():
76
+ _run_directory(file_path, args)
77
+ else:
78
+ _run_single_file(file_path, args)
79
+
80
+
81
+ def _run_single_file(file_path: Path, args: argparse.Namespace) -> None:
82
+ """Execute a single CLM/PCard file."""
83
+ context = parse_context(args.context)
84
+ if file_path.exists():
85
+ context["pcard_dir"] = str(file_path.parent.absolute())
86
+
87
+ try:
88
+ print(f"📄 Loading CLM from: {file_path}")
89
+ if getattr(args, "use_async", False):
90
+ runner = CLMRunner()
91
+ report = asyncio.run(
92
+ asyncio.to_thread(runner.run_file, str(file_path), context)
93
+ )
94
+ else:
95
+ runner = CLMRunner()
96
+ report = runner.run_file(str(file_path), context=context)
97
+
98
+ if args.test:
99
+ _display_test_results(report)
100
+ else:
101
+ print(json.dumps(report, indent=2, default=str))
102
+
103
+ if report["status"] != "success":
104
+ sys.exit(1)
105
+
106
+ except FileNotFoundError:
107
+ print(f"❌ File not found: {file_path}", file=sys.stderr)
108
+ sys.exit(1)
109
+ except (ValueError, TypeError, RuntimeError, yaml.YAMLError) as e:
110
+ print(f"❌ Execution failed: {str(e)}", file=sys.stderr)
111
+ if args.verbose:
112
+ import traceback
113
+
114
+ traceback.print_exc()
115
+ sys.exit(1)
116
+
117
+
118
+ def _run_directory(dir_path: Path, args: argparse.Namespace) -> None:
119
+ """Execute all CLM files in a directory."""
120
+ excluded_dirs = {"test_data", "__pycache__", "node_modules", ".git", ".venv"}
121
+ yaml_files = sorted(
122
+ f
123
+ for f in (
124
+ list(dir_path.rglob("*.yaml"))
125
+ + list(dir_path.rglob("*.yml"))
126
+ + list(dir_path.rglob("*.clm"))
127
+ )
128
+ if not any(part in excluded_dirs for part in f.parts)
129
+ and not f.name.startswith("_")
130
+ )
131
+
132
+ if not yaml_files:
133
+ print(f"❌ No YAML files found in: {dir_path}", file=sys.stderr)
134
+ sys.exit(1)
135
+
136
+ print(f"📁 Running {len(yaml_files)} CLM files in: {dir_path}")
137
+ print("=" * 60)
138
+
139
+ passed = 0
140
+ failed = 0
141
+ skipped = 0
142
+ failures: list[str] = []
143
+
144
+ for i, f in enumerate(yaml_files, 1):
145
+ rel = f.relative_to(dir_path.parent) if dir_path.parent != Path(".") else f
146
+ print(f"\n[{i}/{len(yaml_files)}] {rel}")
147
+
148
+ try:
149
+ with open(f) as fh:
150
+ raw = yaml.safe_load(fh)
151
+ if isinstance(raw, dict):
152
+ meta = raw.get("clm", {}).get("metadata", {})
153
+ if meta.get("skip_in_suite"):
154
+ reason = (
155
+ "requires_server"
156
+ if meta.get("requires_server")
157
+ else "skip_in_suite"
158
+ )
159
+ print(f" ⏭️ SKIPPED ({reason})")
160
+ skipped += 1
161
+ continue
162
+ except (yaml.YAMLError, OSError):
163
+ pass
164
+
165
+ context = parse_context(args.context)
166
+ context["pcard_dir"] = str(f.parent.absolute())
167
+
168
+ try:
169
+ if getattr(args, "use_async", False):
170
+ runner = CLMRunner()
171
+ report = asyncio.run(
172
+ asyncio.to_thread(runner.run_file, str(f), context)
173
+ )
174
+ else:
175
+ runner = CLMRunner()
176
+ report = runner.run_file(str(f), context=context)
177
+
178
+ if args.test:
179
+ _display_test_results(report)
180
+
181
+ if report.get("status") == "success":
182
+ print(" ✅ PASS")
183
+ passed += 1
184
+ else:
185
+ print(" ❌ FAIL")
186
+ failed += 1
187
+ failures.append(str(rel))
188
+
189
+ except (
190
+ FileNotFoundError,
191
+ ValueError,
192
+ TypeError,
193
+ RuntimeError,
194
+ yaml.YAMLError,
195
+ OSError,
196
+ ) as e:
197
+ print(f" ❌ FAIL — {e}")
198
+ failed += 1
199
+ failures.append(str(rel))
200
+
201
+ print(f"\n{'=' * 60}")
202
+ skip_str = f", {skipped} skipped" if skipped else ""
203
+ print(
204
+ f"📊 Summary: {passed} passed, {failed} failed{skip_str} (total: {len(yaml_files)})"
205
+ )
206
+ if failures:
207
+ print("\nFailures:")
208
+ for name in failures:
209
+ print(f" - {name}")
210
+ print()
211
+
212
+ if failed > 0:
213
+ sys.exit(1)
214
+
215
+
216
+ def _display_test_results(report: dict[str, Any]) -> None:
217
+ """Display test results in human-readable format."""
218
+ result = report.get("result", {})
219
+
220
+ print(f"\n{'=' * 60}")
221
+ print(f"📊 Test Results: {report.get('chapter_title', 'Unknown')}")
222
+ print(f"{'=' * 60}")
223
+
224
+ if isinstance(result, dict):
225
+ examples = result.get("examples", [])
226
+ if examples:
227
+ passed = sum(1 for ex in examples if ex.get("consensus", False))
228
+ total = len(examples)
229
+
230
+ for i, ex in enumerate(examples, 1):
231
+ status = "✅" if ex.get("consensus", False) else "❌"
232
+ desc = ex.get("description", f"Example #{i}")
233
+ print(f"{status} {desc}")
234
+
235
+ if not ex.get("consensus", False):
236
+ if "error" in ex:
237
+ print(f" Error: {ex['error']}")
238
+ if "results" in ex:
239
+ print(f" Results: {ex['results']}")
240
+
241
+ print(f"\n{'=' * 60}")
242
+ print(f"Summary: {passed}/{total} PASSED")
243
+ else:
244
+ success = result.get(
245
+ "consensus",
246
+ result.get("success", report.get("status") == "success"),
247
+ )
248
+ status = "✅ PASSED" if success else "❌ FAILED"
249
+ print(f"Result: {status}")
250
+ if "output" in result:
251
+ print(f"Output: {result['output']}")
252
+ else:
253
+ print(f"Result: {result}")
254
+
255
+ print()
256
+
257
+
258
+ def status_command(args: argparse.Namespace) -> None:
259
+ """Display polyglot runtime status."""
260
+ print("\n🌐 Polyglot Runtime Status")
261
+ print("=" * 60)
262
+ RuntimeFactory.print_status(verbose=args.verbose)
263
+ print()
264
+
265
+
266
+ def list_command(args: argparse.Namespace) -> None:
267
+ """List available CLM files."""
268
+ print("\n📚 Available CLM Files")
269
+ print("=" * 60)
270
+
271
+ search_paths = [
272
+ Path("sample_pcards"),
273
+ Path("tests/chapters"),
274
+ Path("chapters"),
275
+ ]
276
+
277
+ found = False
278
+ for search_dir in search_paths:
279
+ if search_dir.exists():
280
+ files = sorted(
281
+ list(search_dir.rglob("*.yaml"))
282
+ + list(search_dir.rglob("*.clm"))
283
+ + list(search_dir.rglob("*.yml"))
284
+ )
285
+
286
+ if files:
287
+ print(f"\n📁 {search_dir}/")
288
+ for f in files:
289
+ rel_path = (
290
+ f.relative_to(search_dir.parent)
291
+ if search_dir.parent != Path(".")
292
+ else f
293
+ )
294
+ print(f" • {rel_path}")
295
+ found = True
296
+
297
+ if not found:
298
+ print("❌ No CLM files found in sample_pcards/ or chapters/")
299
+
300
+ print("\n💡 Usage: python -m mcard.cli run <file>")
301
+ print()
302
+
303
+
304
+ def flow_command(args: argparse.Namespace) -> None:
305
+ """Execute a Flow spec YAML via PTREngine/AsyncPTREngine."""
306
+ file_path = Path(args.file)
307
+ target_hash = args.target
308
+ if not target_hash:
309
+ print("❌ --target is required for flow execution", file=sys.stderr)
310
+ sys.exit(1)
311
+
312
+ inputs = parse_context(getattr(args, "inputs", "{}"))
313
+ if file_path.exists():
314
+ inputs["pcard_dir"] = str(file_path.parent.absolute())
315
+
316
+ try:
317
+ print(f"🧭 Executing Flow from: {file_path} -> target: {target_hash}")
318
+ if getattr(args, "use_async", False):
319
+ aengine = AsyncPTREngine()
320
+ report = asyncio.run(
321
+ aengine.run_flow_file_async(
322
+ str(file_path), target_hash=target_hash, inputs=inputs
323
+ )
324
+ )
325
+ else:
326
+ engine = PTREngine()
327
+ report = engine.run_flow_file(
328
+ str(file_path), target_hash=target_hash, inputs=inputs
329
+ )
330
+
331
+ print(json.dumps(report, indent=2, default=str))
332
+ if report.get("status") != "success":
333
+ sys.exit(1)
334
+
335
+ except FileNotFoundError:
336
+ print(f"❌ File not found: {file_path}", file=sys.stderr)
337
+ sys.exit(1)
338
+ except (ValueError, TypeError, RuntimeError, yaml.YAMLError) as e:
339
+ print(f"❌ Flow execution failed: {str(e)}", file=sys.stderr)
340
+ if args.verbose:
341
+ import traceback
342
+
343
+ traceback.print_exc()
344
+ sys.exit(1)
345
+
346
+
347
+ def launch_command(args: argparse.Namespace) -> None:
348
+ """Launch the Sovereign Node (Discovery + API)"""
349
+ import random
350
+
351
+ try:
352
+ from clm.layer4.api import start_api_server
353
+ except ImportError:
354
+ start_api_server = None
355
+
356
+ node_id = (
357
+ getattr(args, "node_id", None) or f"did:key:pkc_user_{random.randint(100, 999)}"
358
+ )
359
+ from clm.cross_cutting.config.config_constants import DEFAULT_PYTHON_API_PORT
360
+
361
+ port = getattr(args, "port", DEFAULT_PYTHON_API_PORT)
362
+
363
+ print("🚀 Launching Sovereign PKC Node (Python Kernel)")
364
+ print(f"[Kernel] Initialized core execution environment for {node_id}")
365
+
366
+ if start_api_server:
367
+ print(f"[API] Booting backend interface on port {port}...")
368
+ try:
369
+ start_api_server()
370
+ except KeyboardInterrupt:
371
+ print("\nShutting down...")
372
+ sys.exit(0)
373
+ else:
374
+ print("[API] API server module not configured.")
375
+
376
+
377
+ # ─────────────────────────────────────────────────────────────────────────────
378
+ # Main Entry Point
379
+ # ─────────────────────────────────────────────────────────────────────────────
380
+
381
+
382
+ def main() -> None:
383
+ """Main CLI entry point."""
384
+ parser = argparse.ArgumentParser(
385
+ description="MCard CLI - Sovereign CLM and Coordination Engine",
386
+ formatter_class=argparse.RawDescriptionHelpFormatter,
387
+ epilog="""
388
+ Examples:
389
+ python -m mcard.cli run my_clm.yaml
390
+ python -m mcard.cli run my_clm.yaml --context '{"a": 1}'
391
+ python -m mcard.cli run my_clm.yaml --test --verbose
392
+ python -m mcard.cli status --verbose
393
+ python -m mcard.cli list
394
+ """,
395
+ )
396
+
397
+ parser.add_argument(
398
+ "-v", "--verbose", action="store_true", help="Enable verbose output"
399
+ )
400
+
401
+ subparsers = parser.add_subparsers(dest="command", help="Command to execute")
402
+
403
+ # Run Command
404
+ run_parser = subparsers.add_parser(
405
+ "run",
406
+ help="Execute a CLM Chapter/PCard",
407
+ description="Execute a CLM specification from a YAML file.",
408
+ )
409
+ run_parser.add_argument("file", help="Path to the CLM/YAML file")
410
+ run_parser.add_argument(
411
+ "--context",
412
+ "-c",
413
+ default="{}",
414
+ help="JSON string for execution context (default: {})",
415
+ )
416
+ run_parser.add_argument(
417
+ "--test", "-t", action="store_true", help="Display results in test format"
418
+ )
419
+ run_parser.add_argument(
420
+ "-v", "--verbose", action="store_true", help="Enable verbose output"
421
+ )
422
+ run_parser.add_argument(
423
+ "--async",
424
+ dest="use_async",
425
+ action="store_true",
426
+ help="Use AsyncPTREngine for async execution",
427
+ )
428
+
429
+ # Status Command
430
+ status_parser = subparsers.add_parser(
431
+ "status",
432
+ help="Show polyglot runtime status",
433
+ description="Display the status of all polyglot runtimes (Python, JS, Rust, etc.)",
434
+ )
435
+ status_parser.add_argument(
436
+ "-v", "--verbose", action="store_true", help="Show detailed status"
437
+ )
438
+
439
+ # List Command
440
+ list_parser = subparsers.add_parser(
441
+ "list",
442
+ help="List available CLM files",
443
+ description="List CLM files in sample_pcards/ and chapters/ directories.",
444
+ )
445
+ list_parser.add_argument(
446
+ "-v", "--verbose", action="store_true", help="Show detailed listing"
447
+ )
448
+
449
+ # Launch Command
450
+ launch_parser = subparsers.add_parser(
451
+ "launch",
452
+ help="Start the Sovereign Node (Discovery + API)",
453
+ description="Start local API background processes.",
454
+ )
455
+ from clm.cross_cutting.config.config_constants import DEFAULT_PYTHON_API_PORT
456
+
457
+ launch_parser.add_argument(
458
+ "-p",
459
+ "--port",
460
+ type=int,
461
+ default=DEFAULT_PYTHON_API_PORT,
462
+ help="Port to broadcast on mDNS",
463
+ )
464
+ launch_parser.add_argument(
465
+ "-n", "--node-id", type=str, help="DID or Node ID for the Mesh"
466
+ )
467
+
468
+ # Flow Command
469
+ flow_parser = subparsers.add_parser(
470
+ "flow",
471
+ help="Execute a Flow spec YAML",
472
+ description="Run a declarative PCard flow (with optional nested subflows)",
473
+ )
474
+ flow_parser.add_argument("file", help="Path to the Flow YAML file")
475
+ flow_parser.add_argument(
476
+ "--target",
477
+ "-t",
478
+ required=True,
479
+ help="Target MCard hash for the flow",
480
+ )
481
+ flow_parser.add_argument(
482
+ "--inputs",
483
+ "-i",
484
+ default="{}",
485
+ help="JSON string for flow inputs (default: {})",
486
+ )
487
+ flow_parser.add_argument(
488
+ "--async",
489
+ dest="use_async",
490
+ action="store_true",
491
+ help="Use AsyncPTREngine for async flow execution",
492
+ )
493
+
494
+ args = parser.parse_args()
495
+
496
+ if hasattr(args, "verbose") and args.verbose:
497
+ setup_logging(logging.DEBUG)
498
+ else:
499
+ setup_logging(logging.WARNING)
500
+
501
+ if args.command == "run":
502
+ run_command(args)
503
+ elif args.command == "status":
504
+ status_command(args)
505
+ elif args.command == "list":
506
+ list_command(args)
507
+ elif args.command == "launch":
508
+ launch_command(args)
509
+ elif args.command == "flow":
510
+ flow_command(args)
511
+ else:
512
+ parser.print_help()
513
+ print("\n💡 Try: clm run --help")
514
+ sys.exit(1)
515
+
516
+
517
+ if __name__ == "__main__":
518
+ main()
519
+
520
+ # Register evaluate_cmd with Layer 1 callback registry (Dependency Inversion)
521
+ try:
522
+ from clm.layer1.eval_callback import register_evaluate_callback
523
+
524
+ register_evaluate_callback(evaluate_cmd)
525
+ except ImportError:
526
+ pass
527
+
528
+ # Aliasing for clm.layer4.cli.tridb_admin submodule compatibility (DEL-387-03)
529
+ try:
530
+ from clm.layer4 import tridb_admin
531
+ sys.modules["clm.layer4.cli.tridb_admin"] = tridb_admin
532
+ except ImportError:
533
+ pass
534
+
535
+ # Aliasing for clm.layer4.cli.mcard_commands submodule compatibility (DEL-392-03)
536
+ try:
537
+ from clm.layer4 import mcard_commands
538
+ sys.modules["clm.layer4.cli.mcard_commands"] = mcard_commands
539
+ except ImportError:
540
+ pass
541
+
542
+ # Aliasing for clm.layer4.cli action and diff submodules (DEL-396-01)
543
+ try:
544
+ from clm.layer4 import action_commands
545
+ sys.modules["clm.layer4.cli.action_commands"] = action_commands
546
+ from clm.layer4 import diff_commands
547
+ sys.modules["clm.layer4.cli.diff_commands"] = diff_commands
548
+ except ImportError:
549
+ pass