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
+88
View File
@@ -0,0 +1,88 @@
"""External tool capability detection via dynamic plugin scanning."""
import os
import yaml
from typing import Dict, Any, List
def _get_active_plugins() -> List[str]:
"""Scan all plugin roots for active plugins."""
active_plugins = []
plugin_roots = ["/a0/plugins", "/a0/usr/plugins"]
for root in plugin_roots:
if not os.path.isdir(root):
continue
for plugin_name in os.listdir(root):
plugin_dir = os.path.join(root, plugin_name)
if not os.path.isdir(plugin_dir):
continue
plugin_yaml = os.path.join(plugin_dir, "plugin.yaml")
if not os.path.isfile(plugin_yaml):
continue
# Check if plugin is active
is_active = False
if os.path.isfile(os.path.join(plugin_dir, ".toggle-1")):
is_active = True
elif os.path.isfile(os.path.join(plugin_dir, ".toggle-0")):
is_active = False
else:
# No toggle files, check always_enabled
try:
with open(plugin_yaml, "r") as f:
config = yaml.safe_load(f)
if config and config.get("always_enabled", False):
is_active = True
except (yaml.YAMLError) as e:
pass
if is_active:
active_plugins.append(plugin_name)
return active_plugins
def generate_capability_report(config: Dict[str, Any] = None) -> Dict[str, Any]:
"""Generate a capability report for all actively registered tools."""
active_plugins = _get_active_plugins()
report = {}
for name in active_plugins:
report[name] = {
"available": True,
"fallback": "plugin is active",
}
# Add a few standard tools not represented as plugins if they exist in config
if config:
tools_config = config.get("external_tools", {})
for name, cfg in tools_config.items():
if name not in report:
report[name] = {
"available": False,
"fallback": cfg.get("fallback", "not available"),
}
return report
def check_tool(tool_name: str) -> Dict[str, Any]:
"""Return availability for one plugin/tool capability name."""
active_plugins = _get_active_plugins()
if tool_name in active_plugins:
return {"available": True, "fallback": "plugin is active"}
# Also match by declared tool name inside active plugin manifests.
for plugin_name in active_plugins:
plugin_dir = os.path.join("/a0/usr/plugins", plugin_name)
plugin_yaml = os.path.join(plugin_dir, "plugin.yaml")
try:
with open(plugin_yaml, "r", encoding="utf-8") as f:
config = yaml.safe_load(f) or {}
for tool in config.get("tools", []) or []:
if tool.get("name") == tool_name:
return {"available": True, "fallback": f"declared by plugin {plugin_name}"}
except Exception:
continue
return {"available": False, "fallback": "not active or not declared"}