core: Inventar/Placement, Konfig-Validierung, CLI, HTTP-API, LiteLLM-Konfiguration, Beispiel-Skills

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 00:47:13 +02:00
co-authored by Claude Opus 5.5
parent f2da893f71
commit 4cbe313c62
20 changed files with 1085 additions and 19 deletions
+82
View File
@@ -0,0 +1,82 @@
"""Kommandozeile: serve, validate, inventory, placement, registry export."""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
import yaml
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="knaster")
sub = parser.add_subparsers(dest="cmd", required=True)
p_serve = sub.add_parser("serve", help="Router-Service starten")
p_serve.add_argument("--host", default="0.0.0.0")
p_serve.add_argument("--port", type=int, default=8080)
p_val = sub.add_parser("validate", help="Konfiguration prüfen")
p_val.add_argument("--root", default=".")
p_val.add_argument("--site", default="knaster")
p_inv = sub.add_parser("inventory", help="Inventar")
inv_sub = p_inv.add_subparsers(dest="inv_cmd", required=True)
p_col = inv_sub.add_parser("collect", help="lokales System auslesen")
p_col.add_argument("--name")
p_plan = sub.add_parser("placement", help="Placement-Plan")
p_plan.add_argument("--inventory", required=True)
p_plan.add_argument("--catalog", default="catalog")
p_reg = sub.add_parser("registry", help="Registry")
reg_sub = p_reg.add_subparsers(dest="reg_cmd", required=True)
reg_sub.add_parser("export", help="effektiven Stand (inkl. Laufzeitzustand) als YAML ausgeben")
args = parser.parse_args(argv)
if args.cmd == "serve":
import uvicorn
uvicorn.run("knaster.api:create_app", factory=True, host=args.host, port=args.port)
return 0
if args.cmd == "validate":
from .validate import validate_repo
issues = validate_repo(Path(args.root), args.site)
for level, msg in issues:
print(f"{level.upper():8} {msg}")
errors = [i for i in issues if i[0] == "error"]
print(f"{len(errors)} Fehler, {len(issues) - len(errors)} Warnungen")
return 1 if errors else 0
if args.cmd == "inventory":
from .inventory.profile import collect
print(yaml.safe_dump({"nodes": [collect(args.name).model_dump()]}, sort_keys=False, allow_unicode=True))
return 0
if args.cmd == "placement":
from .inventory.placement import load_catalog, load_nodes, plan
roles, models = load_catalog(args.catalog)
result = plan(load_nodes(args.inventory), roles, models)
print(yaml.safe_dump(result.model_dump(), sort_keys=False, allow_unicode=True))
return 1 if any(not u.optional for u in result.unplaced) else 0
if args.cmd == "registry":
from .registry import Registry
from .settings import Settings
from .store import Store
settings = Settings.from_env()
registry = Registry.from_file(settings.site_dir / "registry.yaml", Store(settings.db_url))
print(yaml.safe_dump(registry.export(), sort_keys=False, allow_unicode=True))
return 0
return 2
if __name__ == "__main__":
sys.exit(main())