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
This commit is contained in:
Software Orchestrator
2026-06-16 22:13:06 +00:00
commit 5769c1cd22
236 changed files with 17825 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
"""API: Read audit status."""
from helpers.api import ApiHandler, Request, Response
import os
class AuditStatusGet(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
project_root = input.get("project_root", os.getcwd())
audit_dir = os.path.join(project_root, ".a0", "audit")
audits = {}
if os.path.isdir(audit_dir):
for f in os.listdir(audit_dir):
if f.endswith(".md"):
path = os.path.join(audit_dir, f)
with open(path, "r") as fh:
audits[f] = fh.read()[:500] # first 500 chars
return {"ok": True, "audits": audits, "count": len(audits)}
+10
View File
@@ -0,0 +1,10 @@
"""API: Validate plugin configuration."""
from helpers.api import ApiHandler, Request, Response
import os
from usr.plugins.a0_software_orchestrator.helpers.validators import validate_config
class ConfigValidate(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
config_path = "/a0/usr/plugins/a0_software_orchestrator/default_config.yaml"
result = validate_config(config_path)
return result
+17
View File
@@ -0,0 +1,17 @@
"""API: Read current model routing configuration."""
from helpers.api import ApiHandler, Request, Response
import os
from usr.plugins.a0_software_orchestrator.helpers.model_routing import load_config, list_roles, get_role_preset
class ModelRoutingGet(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
plugin_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
config = load_config(plugin_dir)
roles = list_roles(config)
result = {"roles": {}}
for role in roles:
preset = get_role_preset(role, config)
result["roles"][role] = {"preset": preset}
result["mode"] = config.get("mode", "per_agent_profile")
result["fallback"] = config.get("fallback_to_current_agent_model", True)
return result
+39
View File
@@ -0,0 +1,39 @@
"""API: Save model routing configuration."""
from helpers.api import ApiHandler, Request, Response
import yaml
import os
class ModelRoutingSave(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
role = input.get("role", "")
preset = input.get("preset", "")
project_name = input.get("project_name", "")
agent_profile = input.get("agent_profile", "")
if not role or not preset:
return {"ok": False, "error": "role and preset are required"}
# Update default_config.yaml or per-project config
plugin_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
config_path = os.path.join(plugin_dir, "default_config.yaml")
try:
with open(config_path, "r") as f:
config = yaml.safe_load(f) or {}
except Exception:
config = {}
routing = config.get("model_routing", {})
roles = routing.get("roles", {})
if role not in roles:
roles[role] = {}
roles[role]["preset"] = preset
routing["roles"] = roles
config["model_routing"] = routing
try:
with open(config_path, "w") as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
return {"ok": True, "role": role, "preset": preset}
except Exception as e:
return {"ok": False, "error": str(e)}
+29
View File
@@ -0,0 +1,29 @@
"""API: Read DB-backed project state."""
from __future__ import annotations
import os
from helpers.api import ApiHandler, Request, Response
from usr.plugins.a0_software_orchestrator.helpers.db_state_store import (
get_project_id,
collect_full_state,
)
from usr.plugins.a0_software_orchestrator.helpers.state_store import read_json
class ProjectStateGet(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
project_root = input.get("project_root", os.getcwd())
# Bug 4 Fix: basename-Fallback entfernt. project_name ist Pflicht.
project_name = input.get("project_name")
if not project_name:
return {"ok": False, "error": "project_name is required (basename fallback removed)"}
try:
pid = get_project_id(project_name)
if pid is None:
raise LookupError("project is not registered")
return {"ok": True, "source": "db", "project_id": pid, "state": collect_full_state(pid)}
except Exception as exc:
# Legacy fallback for existing .a0 projects.
state_file = os.path.join(project_root, ".a0", "project_state.json")
state = read_json(state_file, {})
return {"ok": False, "source": "file-fallback", "error": str(exc), "state": state}
+26
View File
@@ -0,0 +1,26 @@
"""API: Trigger tool capability check."""
from helpers.api import ApiHandler, Request, Response
from usr.plugins.a0_software_orchestrator.helpers.tool_capabilities import generate_capability_report, check_tool
import yaml
import os
class ToolCapabilityCheck(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
tool_name = input.get("tool_name", "")
plugin_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
config_path = os.path.join(plugin_dir, "default_config.yaml")
try:
with open(config_path, "r") as f:
config = yaml.safe_load(f) or {}
except Exception:
config = {}
if tool_name:
# Check single tool
status = check_tool(tool_name)
return {"tool": tool_name, **status}
else:
# Full report
report = generate_capability_report(config)
return {"tools": report}