feat(skill): implement multi-agent-mux-orc-onboard skill and orchestrator_uuids exclusion gate (40/40 PASS)
This commit is contained in:
+100
-2
@@ -22,6 +22,7 @@ if [ -z "${BASH_VERSION:-}" ]; then
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
export PYTHONPATH="$SKILL_DIR:${PYTHONPATH:-}"
|
||||
WORKSPACE_ROOT="${WORKSPACE_ROOT:-$(cd "$SKILL_DIR/../.." && pwd)}"
|
||||
AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}"
|
||||
|
||||
@@ -992,6 +993,17 @@ def _validate(d):
|
||||
if iso is not None:
|
||||
if not isinstance(iso, dict) or not iso.get('uuid') or not iso.get('root'):
|
||||
raise SystemExit(f"VALIDATE: herdr_sessions[{i}] {s.get('name')!r} isolation block requires uuid/root")
|
||||
orc_uuids = d.get('orchestrator_uuids')
|
||||
if orc_uuids is not None:
|
||||
if not isinstance(orc_uuids, list):
|
||||
raise SystemExit("VALIDATE: orchestrator_uuids is not a list")
|
||||
seen_orc = set()
|
||||
for u in orc_uuids:
|
||||
if not isinstance(u, str) or not u.strip():
|
||||
raise SystemExit("VALIDATE: orchestrator_uuids items must be non-empty strings")
|
||||
if u in seen_orc:
|
||||
raise SystemExit("VALIDATE: orchestrator_uuids contains duplicate item")
|
||||
seen_orc.add(u)
|
||||
|
||||
def get_terminal_set(d):
|
||||
return {s.get('name'): s.get('status') for s in d.get('herdr_sessions', []) if s.get('status') in ('stopped', 'terminated', 'archived')}
|
||||
@@ -1003,6 +1015,10 @@ def get_all_sessions_status(d):
|
||||
name = s.get('name')
|
||||
ser = json.dumps(s, sort_keys=True)
|
||||
res[name] = hashlib.sha256(ser.encode('utf-8')).hexdigest()
|
||||
orc_uuids = d.get('orchestrator_uuids')
|
||||
if orc_uuids is not None:
|
||||
ser_orc = json.dumps(orc_uuids, sort_keys=True)
|
||||
res['__orchestrator_uuids__'] = hashlib.sha256(ser_orc.encode('utf-8')).hexdigest()
|
||||
return res
|
||||
|
||||
os.makedirs(os.path.dirname(db_path) or '.', exist_ok=True)
|
||||
@@ -1171,6 +1187,76 @@ PYEOF
|
||||
# Returns 0 if valid (passes Stage 1, 2, 3), 1 otherwise.
|
||||
# ---------------------------------------------------------------------------
|
||||
VERIFY_SESSION_PYTHON='
|
||||
_MAM_ORC_CACHE = None
|
||||
|
||||
def mam_orchestrator_uuids():
|
||||
global _MAM_ORC_CACHE
|
||||
if _MAM_ORC_CACHE is not None:
|
||||
return _MAM_ORC_CACHE
|
||||
import os, sys, json, sqlite3, yaml
|
||||
override = os.environ.get("MAM_ORCHESTRATOR_UUIDS")
|
||||
if override is not None:
|
||||
if not override.strip():
|
||||
_MAM_ORC_CACHE = []
|
||||
return _MAM_ORC_CACHE
|
||||
if override.strip().startswith("["):
|
||||
try:
|
||||
parsed = json.loads(override)
|
||||
if isinstance(parsed, list):
|
||||
_MAM_ORC_CACHE = [str(x) for x in parsed if x]
|
||||
return _MAM_ORC_CACHE
|
||||
except Exception:
|
||||
pass
|
||||
_MAM_ORC_CACHE = [x.strip() for x in override.split(",") if x.strip()]
|
||||
return _MAM_ORC_CACHE
|
||||
|
||||
res = []
|
||||
d_obj = None
|
||||
try:
|
||||
if "MAM_STATE_JSON" in os.environ and os.environ.get("MAM_STATE_JSON"):
|
||||
d_obj = json.loads(os.environ.get("MAM_STATE_JSON"))
|
||||
except Exception:
|
||||
d_obj = None
|
||||
|
||||
if d_obj is None or "orchestrator_uuids" not in d_obj:
|
||||
yaml_p = os.environ.get("AGENT_SESSIONS_YAML") or os.environ.get("YAML_PATH")
|
||||
if yaml_p:
|
||||
db_p = os.path.splitext(yaml_p)[0] + ".db"
|
||||
if os.path.exists(db_p):
|
||||
try:
|
||||
conn = sqlite3.connect(db_p, timeout=5.0)
|
||||
r = conn.execute("SELECT data FROM state WHERE id=1").fetchone()
|
||||
if r and r[0]:
|
||||
d_obj = json.loads(r[0])
|
||||
conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
if (d_obj is None or "orchestrator_uuids" not in d_obj) and os.path.exists(yaml_p):
|
||||
try:
|
||||
with open(yaml_p) as f:
|
||||
d_obj = yaml.safe_load(f) or {}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
raw = d_obj.get("orchestrator_uuids") if isinstance(d_obj, dict) else None
|
||||
if raw is not None:
|
||||
if isinstance(raw, list) and all(isinstance(x, str) and x.strip() for x in raw):
|
||||
res = list(raw)
|
||||
else:
|
||||
sys.stderr.write("WARNING: malformed orchestrator_uuids in state, disabling orchestrator exclusion gate\n")
|
||||
res = []
|
||||
_MAM_ORC_CACHE = res
|
||||
return _MAM_ORC_CACHE
|
||||
|
||||
def mam_row_own_uuid(row):
|
||||
if not isinstance(row, dict):
|
||||
return None
|
||||
for k in ["claude_session_id_own", "agy_conversation_id_own", "hermes_conversation_id_own", "cline_conversation_id_own"]:
|
||||
v = row.get(k)
|
||||
if v:
|
||||
return v
|
||||
return None
|
||||
|
||||
def workspace_key(path):
|
||||
import os
|
||||
try:
|
||||
@@ -1204,6 +1290,10 @@ def verify_session_uuid(ws, agent, uuid, row=None, home_dir=None, claude_dir=Non
|
||||
if workspace_key(cwd) != workspace_key(ws):
|
||||
return False
|
||||
|
||||
if mode == "discover" and uuid in mam_orchestrator_uuids():
|
||||
if uuid != mam_row_own_uuid(row):
|
||||
return False
|
||||
|
||||
if (mode == "revalidate" and row.get("session_id_source") == "assigned"
|
||||
and not row.get("session_id_verified")):
|
||||
return True
|
||||
@@ -1238,7 +1328,7 @@ def verify_session_uuid(ws, agent, uuid, row=None, home_dir=None, claude_dir=Non
|
||||
pass
|
||||
if not valid_session:
|
||||
return False
|
||||
if found_cwd and found_cwd != cwd:
|
||||
if found_cwd and workspace_key(found_cwd) != workspace_key(cwd):
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
@@ -1413,8 +1503,16 @@ for s_item in d.get('herdr_sessions', []):
|
||||
if val:
|
||||
running_ids.add(val)
|
||||
|
||||
orchestrator_ids = set(mam_orchestrator_uuids())
|
||||
if target:
|
||||
for s_item in d.get('herdr_sessions', []):
|
||||
if s_item.get('name') == target:
|
||||
own = mam_row_own_uuid(s_item)
|
||||
if own:
|
||||
orchestrator_ids.discard(own)
|
||||
|
||||
def emit(u):
|
||||
if u in running_ids:
|
||||
if u in running_ids or u in orchestrator_ids:
|
||||
return
|
||||
print(u)
|
||||
raise SystemExit(0)
|
||||
|
||||
Reference in New Issue
Block a user