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.
- clm/__init__.py +230 -0
- clm/__main__.py +25 -0
- clm/cross_cutting/__init__.py +50 -0
- clm/cross_cutting/_test_runner.py +36 -0
- clm/cross_cutting/async_utils.py +25 -0
- clm/cross_cutting/cel_builder.py +123 -0
- clm/cross_cutting/cel_converter.py +697 -0
- clm/cross_cutting/cel_engine.py +252 -0
- clm/cross_cutting/cel_ops.py +72 -0
- clm/cross_cutting/cel_ops_db.py +157 -0
- clm/cross_cutting/cel_ops_files.py +99 -0
- clm/cross_cutting/cel_ops_state.py +71 -0
- clm/cross_cutting/cel_ops_strings.py +64 -0
- clm/cross_cutting/cel_resolver.py +63 -0
- clm/cross_cutting/cel_slices.py +56 -0
- clm/cross_cutting/cel_store.py +330 -0
- clm/cross_cutting/clm_logger.py +140 -0
- clm/cross_cutting/config/__init__.py +155 -0
- clm/cross_cutting/config/config_constants.py +392 -0
- clm/cross_cutting/config/env_parameters.py +90 -0
- clm/cross_cutting/config/logging.py +378 -0
- clm/cross_cutting/config/settings.py +504 -0
- clm/cross_cutting/context.py +5 -0
- clm/cross_cutting/domain_models.py +55 -0
- clm/cross_cutting/domain_types.py +61 -0
- clm/cross_cutting/effects.py +67 -0
- clm/cross_cutting/errors.py +153 -0
- clm/cross_cutting/governance.py +331 -0
- clm/cross_cutting/guards.py +41 -0
- clm/cross_cutting/mcard.py +321 -0
- clm/cross_cutting/native.py +185 -0
- clm/cross_cutting/observability.py +289 -0
- clm/cross_cutting/pcard.py +434 -0
- clm/cross_cutting/registry.py +71 -0
- clm/cross_cutting/resources.py +84 -0
- clm/cross_cutting/secrets.py +44 -0
- clm/cross_cutting/subprocess_utils.py +118 -0
- clm/cross_cutting/telemetry.py +164 -0
- clm/cross_cutting/testing/__init__.py +8 -0
- clm/cross_cutting/testing/comparator.py +187 -0
- clm/cross_cutting/testing/datasets.py +87 -0
- clm/cross_cutting/timeutil.py +20 -0
- clm/cross_cutting/types/new_type_check.py +0 -0
- clm/cross_cutting/utils/__init__.py +1 -0
- clm/cross_cutting/utils/url_safety.py +50 -0
- clm/cross_cutting/vcard.py +560 -0
- clm/cross_cutting/writer.py +118 -0
- clm/layer0/README.md +50 -0
- clm/layer0/__init__.py +223 -0
- clm/layer0/algebra.py +60 -0
- clm/layer0/algebra_baldwin.py +133 -0
- clm/layer0/algebra_baldwin_generators.py +36 -0
- clm/layer0/algebra_equivalence.py +262 -0
- clm/layer0/algebra_ingest.py +306 -0
- clm/layer0/algebra_manifest_io.py +156 -0
- clm/layer0/assembler.py +481 -0
- clm/layer0/cel/__init__.py +23 -0
- clm/layer0/cel_eval.py +491 -0
- clm/layer0/codec.py +106 -0
- clm/layer0/context.py +122 -0
- clm/layer0/db.py +160 -0
- clm/layer0/exceptions.py +73 -0
- clm/layer0/fibration.py +106 -0
- clm/layer0/gates.py +50 -0
- clm/layer0/hash.py +80 -0
- clm/layer0/loader.py +826 -0
- clm/layer0/math_utils.py +163 -0
- clm/layer0/mcard.py +96 -0
- clm/layer0/model/__init__.py +0 -0
- clm/layer0/model/action.py +223 -0
- clm/layer0/model/card.py +280 -0
- clm/layer0/model/card_triad.py +427 -0
- clm/layer0/model/compatibility.py +60 -0
- clm/layer0/model/dictionary.py +46 -0
- clm/layer0/model/dots.py +331 -0
- clm/layer0/model/event_producer.py +88 -0
- clm/layer0/model/g_time.py +89 -0
- clm/layer0/model/handle.py +163 -0
- clm/layer0/model/hash/__init__.py +6 -0
- clm/layer0/model/hash/algorithms/__init__.py +3 -0
- clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
- clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
- clm/layer0/model/hash/constants.py +53 -0
- clm/layer0/model/hash/enums.py +60 -0
- clm/layer0/model/hash/validator.py +307 -0
- clm/layer0/model/interpreter.py +275 -0
- clm/layer0/model/pagination.py +45 -0
- clm/layer0/model/pcard.py +716 -0
- clm/layer0/model/schema.py +44 -0
- clm/layer0/model/utils/__init__.py +1 -0
- clm/layer0/model/utils/content_analyzer.py +152 -0
- clm/layer0/model/validators/__init__.py +1 -0
- clm/layer0/model/validators/base_validator.py +44 -0
- clm/layer0/model/validators/binary_validator.py +66 -0
- clm/layer0/model/validators/text_validator.py +82 -0
- clm/layer0/model/validators/validation_registry.py +49 -0
- clm/layer0/model/vcard.py +823 -0
- clm/layer0/model/vcard_ext/__init__.py +39 -0
- clm/layer0/model/vcard_ext/core.py +60 -0
- clm/layer0/model/vcard_ext/network.py +23 -0
- clm/layer0/model/vcard_ext/observability.py +63 -0
- clm/layer0/model/vcard_ext/storage.py +60 -0
- clm/layer0/model/vcard_ext/vendors.py +211 -0
- clm/layer0/model/vcard_sandwich.py +119 -0
- clm/layer0/model/vcard_vocabulary.py +463 -0
- clm/layer0/model/workflow.py +274 -0
- clm/layer0/narrative.py +431 -0
- clm/layer0/ontology/collection.py +125 -0
- clm/layer0/parser.py +429 -0
- clm/layer0/relations.py +73 -0
- clm/layer0/rule_evaluator.py +251 -0
- clm/layer0/schema/__init__.py +38 -0
- clm/layer0/schema/ddl.py +97 -0
- clm/layer0/templates/abstract.yaml +99 -0
- clm/layer0/templates/balanced.yaml +253 -0
- clm/layer0/templates/concrete.yaml +172 -0
- clm/layer0/type_registry.py +223 -0
- clm/layer0/types.py +204 -0
- clm/layer0/utils.py +886 -0
- clm/layer0/verifier_core.py +262 -0
- clm/layer1/__init__.py +31 -0
- clm/layer1/action_dispatcher.py +275 -0
- clm/layer1/adapter_registry.py +233 -0
- clm/layer1/algebra_baldwin_generators.py +192 -0
- clm/layer1/arrow_compiler.py +525 -0
- clm/layer1/batch_processor.py +152 -0
- clm/layer1/cel/__init__.py +27 -0
- clm/layer1/cel/builder.py +173 -0
- clm/layer1/engine.py +759 -0
- clm/layer1/engine_async.py +89 -0
- clm/layer1/eval_callback.py +49 -0
- clm/layer1/gate_composer.py +229 -0
- clm/layer1/hoare_sandwich.py +298 -0
- clm/layer1/identity_guard.py +348 -0
- clm/layer1/matrix.py +138 -0
- clm/layer1/neural_runtime.py +221 -0
- clm/layer1/operations/__init__.py +123 -0
- clm/layer1/operations/augment.py +156 -0
- clm/layer1/operations/base.py +109 -0
- clm/layer1/operations/builtins.py +338 -0
- clm/layer1/operations/dispatch.py +144 -0
- clm/layer1/operations/exclude.py +107 -0
- clm/layer1/operations/handle.py +197 -0
- clm/layer1/operations/identity.py +139 -0
- clm/layer1/operations/invert.py +66 -0
- clm/layer1/operations/loader.py +116 -0
- clm/layer1/operations/manipulators/__init__.py +23 -0
- clm/layer1/operations/manipulators/document.py +211 -0
- clm/layer1/operations/manipulators/media.py +134 -0
- clm/layer1/operations/manipulators/structured.py +159 -0
- clm/layer1/operations/manipulators/tabular.py +334 -0
- clm/layer1/operations/port.py +65 -0
- clm/layer1/operations/services.py +529 -0
- clm/layer1/operations/split.py +117 -0
- clm/layer1/operations/substitute.py +75 -0
- clm/layer1/petri.py +1052 -0
- clm/layer1/pocketflow_orchestrator.py +408 -0
- clm/layer1/pocketflow_scheduler.py +519 -0
- clm/layer1/protocols.py +197 -0
- clm/layer1/runtime_adapter.py +718 -0
- clm/layer1/runtimes/__init__.py +71 -0
- clm/layer1/runtimes/_generated_assertions.py +125 -0
- clm/layer1/runtimes/_generated_types.py +42 -0
- clm/layer1/runtimes/base.py +265 -0
- clm/layer1/runtimes/binary.py +101 -0
- clm/layer1/runtimes/factory.py +203 -0
- clm/layer1/runtimes/javascript.py +321 -0
- clm/layer1/runtimes/javascript_runtime.js +33 -0
- clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
- clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
- clm/layer1/runtimes/lambda_calc.py +126 -0
- clm/layer1/runtimes/python.py +288 -0
- clm/layer1/runtimes/python_runtime.py +41 -0
- clm/layer1/runtimes/script.py +114 -0
- clm/layer1/sandbox.py +334 -0
- clm/layer1/savepoint_guard.py +136 -0
- clm/layer1/sparse_net.py +122 -0
- clm/layer1/spec_tester.py +165 -0
- clm/layer1/store.py +295 -0
- clm/layer1/test_runner.py +498 -0
- clm/layer1/type_inspector.py +166 -0
- clm/layer1/verifier.py +772 -0
- clm/layer1/vm.py +91 -0
- clm/layer2/__init__.py +78 -0
- clm/layer2/card_collection.py +678 -0
- clm/layer2/classifier.py +479 -0
- clm/layer2/engine/__init__.py +1 -0
- clm/layer2/engine/abstract_sql_engine.py +320 -0
- clm/layer2/engine/base.py +193 -0
- clm/layer2/engine/duckdb_engine.py +576 -0
- clm/layer2/engine/sqlite_engine.py +518 -0
- clm/layer2/fiber/__init__.py +31 -0
- clm/layer2/fiber/context.py +89 -0
- clm/layer2/fiber/disposable.py +163 -0
- clm/layer2/fiber/fiber.py +125 -0
- clm/layer2/fiber/hoare.py +191 -0
- clm/layer2/file_io.py +376 -0
- clm/layer2/file_registrar.py +77 -0
- clm/layer2/ingest.py +202 -0
- clm/layer2/lineage.py +322 -0
- clm/layer2/mcard_fs.py +262 -0
- clm/layer2/merkle.py +11 -0
- clm/layer2/mime.py +244 -0
- clm/layer2/mime_detector.py +245 -0
- clm/layer2/private_collection.py +118 -0
- clm/layer2/shared_store.py +11 -0
- clm/layer2/storage/__init__.py +190 -0
- clm/layer2/storage/db_bitemporal.py +141 -0
- clm/layer2/storage/db_driver.py +331 -0
- clm/layer2/storage/db_hyperlinks.py +214 -0
- clm/layer2/storage/db_pool.py +139 -0
- clm/layer2/storage/db_repository.py +229 -0
- clm/layer2/storage/savepoint.py +78 -0
- clm/layer2/storage/sqlite_wal.py +74 -0
- clm/layer2/tridb.py +245 -0
- clm/layer2/vcard_receipt.py +71 -0
- clm/layer2/vfs.py +17 -0
- clm/layer3/__init__.py +141 -0
- clm/layer3/agency/__init__.py +19 -0
- clm/layer3/agency/config.py +220 -0
- clm/layer3/agency/providers/__init__.py +15 -0
- clm/layer3/agency/providers/base.py +91 -0
- clm/layer3/agency/providers/mlc_llm.py +169 -0
- clm/layer3/agency/providers/ollama.py +203 -0
- clm/layer3/agency/router.py +71 -0
- clm/layer3/agency/runtime.py +524 -0
- clm/layer3/gateway.py +353 -0
- clm/layer3/open_interpreter_adapter.py +159 -0
- clm/layer3/rag/__init__.py +70 -0
- clm/layer3/rag/cli.py +228 -0
- clm/layer3/rag/config.py +153 -0
- clm/layer3/rag/embeddings/__init__.py +16 -0
- clm/layer3/rag/embeddings/base.py +79 -0
- clm/layer3/rag/embeddings/ollama.py +211 -0
- clm/layer3/rag/embeddings/vision.py +290 -0
- clm/layer3/rag/engine.py +276 -0
- clm/layer3/rag/graph/__init__.py +22 -0
- clm/layer3/rag/graph/community.py +198 -0
- clm/layer3/rag/graph/engine.py +433 -0
- clm/layer3/rag/graph/extractor.py +255 -0
- clm/layer3/rag/graph/schema.py +115 -0
- clm/layer3/rag/graph/store.py +641 -0
- clm/layer3/rag/indexer.py +333 -0
- clm/layer3/rag/llm_providers.json +52 -0
- clm/layer3/rag/semantic_versioning.py +313 -0
- clm/layer3/rag/vector/__init__.py +28 -0
- clm/layer3/rag/vector/handle_vector_store.py +749 -0
- clm/layer3/rag/vector/schema.py +151 -0
- clm/layer3/rag/vector/store.py +632 -0
- clm/layer3/reticulum/__init__.py +55 -0
- clm/layer3/reticulum/bridge.py +74 -0
- clm/layer3/reticulum/daemon.py +88 -0
- clm/layer3/reticulum/discovery.py +164 -0
- clm/layer3/reticulum/identity.py +107 -0
- clm/layer3/reticulum/media.py +148 -0
- clm/layer3/reticulum/transport.py +133 -0
- clm/layer3/satori/__init__.py +209 -0
- clm/layer3/satori/alpha_conversion.py +168 -0
- clm/layer3/satori/beta_reduction.py +359 -0
- clm/layer3/satori/continuation.py +38 -0
- clm/layer3/satori/eta_conversion.py +205 -0
- clm/layer3/satori/free_variables.py +163 -0
- clm/layer3/satori/io_effects.py +370 -0
- clm/layer3/satori/lambda_runtime.py +726 -0
- clm/layer3/satori/lambda_term.py +230 -0
- clm/layer3/satori/sheaf_audit.py +261 -0
- clm/layer3/satori/speech_act.py +279 -0
- clm/layer4/README.md +9 -0
- clm/layer4/__init__.py +67 -0
- clm/layer4/_sovereign_executor.py +580 -0
- clm/layer4/action_commands.py +719 -0
- clm/layer4/api.py +236 -0
- clm/layer4/bootstrap/__init__.py +13 -0
- clm/layer4/bootstrap/bootstrapper.py +118 -0
- clm/layer4/bootstrap/cleanup.py +44 -0
- clm/layer4/bootstrap/clm_hooks.py +49 -0
- clm/layer4/bootstrap/genesis.py +77 -0
- clm/layer4/bootstrap/injection.py +125 -0
- clm/layer4/cli.py +549 -0
- clm/layer4/collection_manager.py +553 -0
- clm/layer4/commands/__init__.py +81 -0
- clm/layer4/commands/action_cmd.py +42 -0
- clm/layer4/commands/check_cmd.py +82 -0
- clm/layer4/commands/envelope.py +73 -0
- clm/layer4/commands/evaluate_cmd.py +224 -0
- clm/layer4/commands/mcard_cmd.py +24 -0
- clm/layer4/commands/petri_cmd.py +92 -0
- clm/layer4/commands/tridb_cmd.py +319 -0
- clm/layer4/commands/version_cmd.py +27 -0
- clm/layer4/diff_commands.py +167 -0
- clm/layer4/eoa_sponsor.py +232 -0
- clm/layer4/events.py +69 -0
- clm/layer4/flux_gateway.py +133 -0
- clm/layer4/gateway.py +91 -0
- clm/layer4/loader.py +307 -0
- clm/layer4/mcard_commands.py +166 -0
- clm/layer4/membrane.py +273 -0
- clm/layer4/navigation.py +50 -0
- clm/layer4/protocol/protocol_entry_python.py +108 -0
- clm/layer4/protocol/python_sync.py +126 -0
- clm/layer4/runner.py +150 -0
- clm/layer4/satori.py +262 -0
- clm/layer4/server/python_sync_client.py +150 -0
- clm/layer4/server/python_sync_server.py +139 -0
- clm/layer4/server/service_api.py +315 -0
- clm/layer4/server/start_servers.py +107 -0
- clm/layer4/server/stop_servers.py +24 -0
- clm/layer4/simulated_optimization_fix.py +0 -0
- clm/layer4/storage.py +463 -0
- clm/layer4/tridb_admin.py +268 -0
- clm/layer4/websocket/test_ws_client.py +104 -0
- clm/layer4/websocket/test_ws_server.py +138 -0
- clm/layer4/websocket/ws_server_local.py +160 -0
- clm/layer5/__init__.py +51 -0
- clm/layer5/async_batch_writer.py +133 -0
- clm/layer5/learning.py +276 -0
- clm/layer5/telemetry_hook.py +107 -0
- clm/layer5/type_lattice.py +238 -0
- clm/py.typed +0 -0
- clm/schemas/__init__.py +652 -0
- clm/schemas/abstract_face_schema.yaml +77 -0
- clm/schemas/cel_schema.yaml +416 -0
- clm/schemas/lifecycle/__init__.py +45 -0
- clm/schemas/lifecycle/models.py +123 -0
- clm/schemas/lifecycle/service.py +364 -0
- clm/schemas/mcard_schema.sql +192 -0
- clm/schemas/mcard_vector_schema.sql +283 -0
- clm/schemas/mlp-context-v1.json +91 -0
- clm_kernel-0.0.0.dist-info/METADATA +121 -0
- clm_kernel-0.0.0.dist-info/RECORD +333 -0
- clm_kernel-0.0.0.dist-info/WHEEL +4 -0
- clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
- 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
|