Files
Software Orchestrator 5769c1cd22 Initial commit: a0_software_orchestrator v1.0
- Auto-Registration-Bug behoben (register_project/get_project_id/resolve_project Trennung)
- 25 Tests gruen (Pytest)
- block_compactor-Tool refactored (Option B: Soft-Check statt Hard-Block)
- 4 Restbaustellen gefixt
- DB-Schema: plugin_settings-Tabelle hinzugefuegt
- 3 Schattenprojekte aus DB geloescht
- Plan v3 + Refactor-Plan + Worklog dokumentiert
2026-06-16 22:13:06 +00:00

159 lines
5.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tool: create/read/update/validate project manifests (DB-backed, replaces .a0/manifests/*.json)."""
from __future__ import annotations
import json
import os
from typing import Any, Dict
from helpers.tool import Tool, Response
from usr.plugins.a0_software_orchestrator.helpers.db_state_store import get_project_id, get_kv, set_kv, list_kv_keys
from usr.plugins.a0_software_orchestrator.helpers.manifest_schema import PROJECT_MANIFEST_SCHEMA, DEPLOYMENT_MANIFEST_SCHEMA
from usr.plugins.a0_software_orchestrator.helpers.exceptions import PluginDBError
def _resolve_name(project_name: str = "", project_root: str = "") -> str:
if project_name:
return project_name.strip()
if project_root:
return os.path.basename(project_root.rstrip("/"))
return os.path.basename(os.getcwd())
def _schema_for(manifest_type: str) -> Dict[str, Any]:
if manifest_type == "project":
return PROJECT_MANIFEST_SCHEMA
if manifest_type == "deployment":
return DEPLOYMENT_MANIFEST_SCHEMA
return {}
def _validate(data: Dict[str, Any], schema: Dict[str, Any]) -> list[str]:
"""Lightweight required-keys validator (subset of JSON-Schema)."""
errors = []
if not isinstance(data, dict):
return [f"manifest must be a JSON object, got {type(data).__name__}"]
required = schema.get("required", [])
for key in required:
if key not in data:
errors.append(f"missing required field: {key!r}")
return errors
class RepoManifest(Tool):
"""Create, read, update, list or validate project/deployment/quality manifests.
Args (kwargs):
project_name (str): Projektname (bevorzugt).
project_root (str): Legacy wird zu basename() aufgelöst.
manifest_type (str): "project" (default), "deployment", "quality".
action (str): "create" (default), "read", "update", "list", "validate".
data (str|dict): JSON-string oder dict (für create/update).
"""
async def execute(
self,
project_name: str = "",
project_root: str = "",
manifest_type: str = "project",
action: str = "create",
data: str = "",
**kwargs,
):
name = _resolve_name(project_name, project_root)
try:
pid = get_project_id(name)
if pid is None:
raise LookupError(f"project '{name}' is not registered")
except (ValueError, LookupError) as e:
return Response(message=f"ERROR: {e}", break_loop=False)
except PluginDBError as e:
return Response(message=f"Database error: {e}", break_loop=False)
key = f"manifest_{manifest_type}"
schema = _schema_for(manifest_type)
if action == "list":
keys = [k for k in list_kv_keys(pid) if k.startswith("manifest_")]
if not keys:
return Response(
message=f"No manifests for project {name!r}.",
break_loop=False,
)
return Response(
message=f"Manifests for {name!r}: {', '.join(keys)}",
break_loop=False,
)
if action == "read":
manifest = get_kv(pid, key, default=None)
if manifest is None:
return Response(
message=f"No {manifest_type!r} manifest for project {name!r}.",
break_loop=False,
)
return Response(
message=json.dumps(manifest, indent=2, ensure_ascii=False),
break_loop=False,
)
if action in ("create", "update"):
# Parse data
if not data:
return Response(
message="ERROR: 'data' required for create/update (JSON string or dict)",
break_loop=False,
)
if isinstance(data, str):
try:
parsed = json.loads(data)
except json.JSONDecodeError as e:
return Response(
message=f"ERROR: 'data' is not valid JSON: {e}",
break_loop=False,
)
else:
parsed = data
# Validate against schema (if known)
if schema:
errors = _validate(parsed, schema)
if errors:
return Response(
message=f"ERROR: manifest validation failed: {errors}",
break_loop=False,
)
set_kv(pid, key, parsed)
return Response(
message=f"{manifest_type!r} manifest saved for project {name!r} (key={key!r}).",
break_loop=False,
)
if action == "validate":
manifest = get_kv(pid, key, default=None)
if manifest is None:
return Response(
message=f"No {manifest_type!r} manifest to validate for project {name!r}.",
break_loop=False,
)
if not schema:
return Response(
message=f"No schema defined for {manifest_type!r}; cannot validate.",
break_loop=False,
)
errors = _validate(manifest, schema)
if errors:
return Response(
message=f"Validation FAILED: {errors}",
break_loop=False,
)
return Response(
message=f"Validation PASSED for {manifest_type!r} manifest of project {name!r}.",
break_loop=False,
)
return Response(
message=f"Unknown action {action!r}. Supported: create, read, update, list, validate",
break_loop=False,
)