Files
box/bin/super-cli.py
T

7668 lines
337 KiB
Python
Executable File
Raw 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.
#!/usr/bin/env python3
"""super-cli.py — Unified Off-Board Orchestrator CLI for NetVM & Box.
Empowers 'off-board super' to govern, task, and observe the fleet of
autonomous browser agents (muse, pip, 646, opm) on bl and interface
with the Google Cloud VM web surfaces.
Domains:
super muse-choices — Muse TUI A/B/C auto-answer daemon (on/off/status/logs)
super fleet — Node health, CDP status, active tabs, watch, restart, heal
super watchdog — Watchdog timers: status, trigger runs
super dm — Inter-agent DMs, work orders ([WO]), acks, live log tail
super thread — Inspect agent main chats, sidechats, and scrollbacks
super job — Manage scheduled jobs, systemd timers, triggers, logs
super web — Probe VM web surfaces (box.muse-dev.online), auth, sync
super loop — Intrinsic loop strategy, fleet loop health, break taxonomy, vars
super strat — Shortcut to inspect & configure loop modulation strategies
super vars — Shortcut to inspect & adjust runtime control variables
Usage:
super fleet [status|watch|restart|cdp|heal]
super watchdog [status|run <node|relay>]
super dm [send|wo|ack|log|tail]
super thread [list|view]
super job [list|status|run|log|create|enable|disable|delete]
super web [health|test-auth|sync]
super loop [status|health|breaks|strat|vars|close|nudge|sweep|harvest|remediate]
super strat [show|set|reset|eval]
super vars [list|get|set|reset|history|rollback]
"""
import argparse
import hashlib
import json
import os
import re
import shutil
import subprocess
import sys
import time
import urllib.error
import urllib.request
from datetime import datetime, timezone
from pathlib import Path
# Paths
NETVM_ROOT = Path("/home/super/Projects/NetVM")
BIN_DIR = NETVM_ROOT / "bin"
JOBS_DIR = NETVM_ROOT / "jobs"
TRANSFERS_DIR = NETVM_ROOT / "transfers"
DM_LOG = NETVM_ROOT / "dm-log.jsonl"
JOB_LOG = NETVM_ROOT / "job-log.jsonl"
CTL_LOG = NETVM_ROOT / "box-ctl.jsonl"
REGISTRY_FILE = NETVM_ROOT / "NODES.md"
CHAT_HISTORY_LOG = NETVM_ROOT / "logs" / "chat-history.jsonl"
WATERMARKS_FILE = NETVM_ROOT / "siphon-watermarks.json"
FOLLOWUPS_FILE = NETVM_ROOT / "followups.json"
JOB_SIDECHATS_FILE = NETVM_ROOT / "job-sidechats.json"
RESPONSE_HARVESTER_PY = BIN_DIR / "response-harvester.py"
FOLLOWUP_SWEEPER_PY = BIN_DIR / "followup-sweeper.py"
PIPELINES_FILE = NETVM_ROOT / "pipelines.json"
JOB_DISPATCH_PY = BIN_DIR / "job-dispatch.py"
# Agent Constants
VALID_NODES = ["muse", "pip", "646", "opm", "def", "dev"]
DEFAULT_SENDER = "super"
DEFAULT_AGENT_SIDECHATS = {
"646": "646 tasks",
"opm": "heartbeat",
"pip": "646-pip-coord",
"muse": "muse tasks",
}
MUSE_TMUX_LOG_DIR = NETVM_ROOT / "logs" / "tmux"
# ---------------------------------------------------------------------------
# ANSI Color & Formatting Engine
# ---------------------------------------------------------------------------
USE_COLOR = sys.stdout.isatty() and os.environ.get("NO_COLOR") is None
def _c(code: str, text: str) -> str:
return f"\033[{code}m{text}\033[0m" if USE_COLOR else str(text)
def c_bold(s: str) -> str: return _c("1", s)
def c_dim(s: str) -> str: return _c("2", s)
def c_green(s: str) -> str: return _c("32", s)
def c_red(s: str) -> str: return _c("31", s)
def c_yellow(s: str) -> str: return _c("33", s)
def c_blue(s: str) -> str: return _c("34", s)
def c_magenta(s: str) -> str: return _c("35", s)
def c_cyan(s: str) -> str: return _c("36", s)
def badge_ok(s: str = "UP") -> str: return c_green(f"● {s}")
def badge_warn(s: str = "WARN") -> str: return c_yellow(f"● {s}")
def badge_err(s: str = "DOWN") -> str: return c_red(f"● {s}")
def badge_dim(s: str) -> str: return c_dim(f"○ {s}")
def print_table(headers: list, rows: list, alignments: list = None):
"""Print an aligned tabular display with clean ANSI formatting."""
if not rows:
print(c_dim(" (no records found)"))
return
num_cols = len(headers)
alignments = alignments or ["left"] * num_cols
# Calculate max visual length per column (stripping ANSI escapes)
strip_ansi = re.compile(r"\033\[[0-9;]*m")
def vlen(s):
return len(strip_ansi.sub("", str(s)))
col_widths = [vlen(h) for h in headers]
for row in rows:
for i in range(num_cols):
val = str(row[i]) if i < len(row) else ""
col_widths[i] = max(col_widths[i], vlen(val))
# Header
hdr_parts = []
sep_parts = []
for i, h in enumerate(headers):
w = col_widths[i]
align = alignments[i]
pad = w - vlen(h)
if align == "right":
hdr_parts.append(" " * pad + c_bold(h))
else:
hdr_parts.append(c_bold(h) + " " * pad)
sep_parts.append("─" * w)
print(" " + " ".join(hdr_parts))
print(" " + c_dim(" ".join(sep_parts)))
# Rows
for row in rows:
row_parts = []
for i in range(num_cols):
val = str(row[i]) if i < len(row) else ""
w = col_widths[i]
align = alignments[i]
pad = max(0, w - vlen(val))
if align == "right":
row_parts.append(" " * pad + val)
else:
row_parts.append(val + " " * pad)
print(" " + " ".join(row_parts))
def parse_relative_time(ts_str: str) -> str:
"""Convert ISO timestamp to short relative time (e.g. 5m ago, 2h ago)."""
if not ts_str:
return "-"
try:
dt = datetime.fromisoformat(ts_str.replace("Z", "+00:00"))
now = datetime.now(timezone.utc)
diff = int((now - dt).total_seconds())
if diff < 0:
return "just now"
if diff < 60:
return f"{diff}s ago"
if diff < 3600:
return f"{diff // 60}m ago"
if diff < 86400:
return f"{diff // 3600}h ago"
return f"{diff // 86400}d ago"
except Exception:
return ts_str[:16].replace("T", " ")
# ---------------------------------------------------------------------------
# Registry & Network Helpers
# ---------------------------------------------------------------------------
def get_node_network_info(node: str) -> dict:
"""Compute deterministic veth/peer IP and load pinned CDP port."""
tag = hashlib.sha256(node.encode()).hexdigest()[:8]
idx = int(tag[:3], 16) % 200 + 10
gw_ip = f"10.201.{idx}.1"
peer_ip = f"10.201.{idx}.2"
# Pinned ports from NODES.md registry
pinned_ports = {
"muse": 9410,
"pip": 9420,
"646": 9430,
"opm": 9440,
"def": 9450,
"dev": 9455,
}
cdp_port = pinned_ports.get(node, 9222 + int(tag[4:7], 16) % 2000)
return {
"node": node,
"netns": f"warp-{node}",
"tag": tag,
"gw_ip": gw_ip,
"peer_ip": peer_ip,
"cdp_port": cdp_port,
}
def probe_cdp_status(peer_ip: str, cdp_port: int, timeout: float = 1.5) -> dict:
"""Probe Chromium DevTools protocol on peer IP."""
url = f"http://{peer_ip}:{cdp_port}/json/version"
t0 = time.time()
try:
req = urllib.request.Request(url, headers={"User-Agent": "super-cli/1.0"})
with urllib.request.urlopen(req, timeout=timeout) as resp:
elapsed_ms = int((time.time() - t0) * 1000)
if resp.status == 200:
data = json.load(resp)
return {
"ok": True,
"latency_ms": elapsed_ms,
"browser": data.get("Browser", "Chromium"),
}
except Exception as e:
return {"ok": False, "error": str(e), "latency_ms": None}
return {"ok": False, "error": "unknown error", "latency_ms": None}
def fetch_active_tab(peer_ip: str, cdp_port: int, timeout: float = 1.5) -> dict:
"""Retrieve title and URL of the active browser page."""
url = f"http://{peer_ip}:{cdp_port}/json/list"
try:
req = urllib.request.Request(url, headers={"User-Agent": "super-cli/1.0"})
with urllib.request.urlopen(req, timeout=timeout) as resp:
tabs = json.load(resp)
pages = [t for t in tabs if t.get("type") == "page"]
if pages:
return {
"title": pages[0].get("title", ""),
"url": pages[0].get("url", ""),
}
except Exception:
pass
return {"title": "-", "url": "-"}
def check_process_alive(node: str) -> bool:
"""Check if Chromium process exists for the node's profile."""
try:
res = subprocess.run(
["pgrep", "-f", f"chrome-box/profiles/{node}"],
capture_output=True, text=True, timeout=2
)
return res.returncode == 0
except Exception:
return False
def get_queue_depth(node: str) -> int:
"""Check active flock tickets in /tmp/cdp-queue/<node>/."""
q_dir = Path(f"/tmp/cdp-queue/{node}")
if not q_dir.exists():
return 0
try:
tickets = [f for f in q_dir.iterdir() if f.name.startswith("ticket-")]
return len(tickets)
except Exception:
return 0
# ---------------------------------------------------------------------------
# Domain: FLEET
# ---------------------------------------------------------------------------
def _host_evidence_for(results):
"""Host watchdog evidence, or None when unneeded/unavailable.
Queried only when at least one node is fully blind (both local
probes negative). Never raises: evidence must not break status.
"""
if not any(not r["proc_alive"] and not r["cdp_ok"] for r in results):
return None
try:
import host_evidence
return host_evidence.collect([r["node"] for r in results])
except Exception:
return None
def _resolve_statuses(results) -> None:
"""Attach effective status/source/evidence to each collected node.
proc_alive/cdp_ok keep their local-probe meaning; status is the
display verdict. Host evidence only decides the fully-blind pattern
(both local probes negative); live local signals always win.
"""
try:
import host_evidence
have_mod = True
except ImportError:
have_mod = False
ev_map = _host_evidence_for(results) if have_mod else None
for r in results:
ev = (ev_map or {}).get(r["node"]) if ev_map else None
if not r["proc_alive"] and r["cdp_ok"]:
# CDP answers: the browser is definitionally alive even when
# pgrep cannot see it (PID-blind shell, renamed profile path).
r["status"], r["source"] = "ACTIVE", "local"
elif r["proc_alive"] and not r["cdp_ok"]:
r["status"], r["source"] = "CDP_DOWN", "local"
elif r["proc_alive"] and r["cdp_ok"]:
r["status"], r["source"] = "ACTIVE", "local"
elif ev is None:
r["status"], r["source"] = "STOPPED", "local"
else:
r["status"], r["source"] = host_evidence.effective_status(
False, False, ev.get("browser", "unknown"),
ev.get("cdp", "unknown"))
r["evidence"] = ev
def collect_fleet_data() -> list:
results = []
for node in VALID_NODES:
info = get_node_network_info(node)
proc_alive = check_process_alive(node)
cdp = probe_cdp_status(info["peer_ip"], info["cdp_port"])
tab = fetch_active_tab(info["peer_ip"], info["cdp_port"]) if cdp["ok"] else {"title": "-", "url": "-"}
q_depth = get_queue_depth(node)
approval_pending = False
approval_detail = None
if cdp["ok"] and ("(1)" in tab.get("title", "") or "approval" in tab.get("title", "").lower()):
try:
import approvals
app_info = approvals.inspect_node_approvals(node)
if app_info.get("has_pending"):
approval_pending = True
approval_detail = app_info
except Exception:
pass
results.append({
"node": node,
"netns": info["netns"],
"peer_ip": info["peer_ip"],
"cdp_port": info["cdp_port"],
"proc_alive": proc_alive,
"cdp_ok": cdp["ok"],
"latency_ms": cdp["latency_ms"],
"title": tab["title"],
"url": tab["url"],
"queue_depth": q_depth,
"approval_pending": approval_pending,
"approval_detail": approval_detail,
})
_resolve_statuses(results)
return results
def cmd_fleet_status(args):
data = collect_fleet_data()
if args.json:
print(json.dumps({"ok": True, "fleet": data}, indent=2))
return
print("\n" + c_bold("=== NETVM FLEET STATUS ===") + c_dim(f" ({datetime.now().strftime('%H:%M:%S')} local)\n"))
# Top-line host stability badge
try:
sys.path.insert(0, str(NETVM_ROOT / "watchers"))
import importlib.util
spec = importlib.util.spec_from_file_location("box_stability_watcher", str(NETVM_ROOT / "watchers" / "box-stability-watcher.py"))
bsw = importlib.util.module_from_spec(spec)
spec.loader.exec_module(bsw)
m = bsw.get_system_metrics()
load_str = f"Load: {m['load_1m']} (1m) | {m['load_5m']} (5m) [Cores: {m['cpu_count']}]"
ram_str = f"RAM: {m['ram_used_pct']}%"
if m['load_1m'] < 20 and m['ram_used_pct'] < 80:
stab_badge = badge_ok("STABLE")
elif m['load_1m'] >= 60 or m['ram_used_pct'] >= 95:
stab_badge = badge_err("EMERGENCY")
else:
stab_badge = badge_warn("ELEVATED")
print(f" HOST {c_bold('bl')}: {stab_badge} {c_dim(load_str + ' ' + ram_str)}\n")
except Exception:
pass
headers = ["NODE", "STATUS", "PEER IP:PORT", "LATENCY", "QUEUE", "ACTIVE PAGE / THREAD"]
rows = []
has_any_approval = False
for item in data:
# Status calculation (effective status; see _resolve_statuses)
if item.get("approval_pending"):
status = badge_warn("APPROVAL_REQ")
has_any_approval = True
elif item.get("status") == "ACTIVE":
status = badge_ok("ACTIVE")
elif item.get("status") == "CDP_DOWN":
status = badge_warn("CDP_DOWN")
elif item.get("status") == "UNKNOWN":
status = badge_dim("UNKNOWN")
else:
status = badge_err("STOPPED")
lat = f"{item['latency_ms']}ms" if item["latency_ms"] is not None else "-"
q = str(item["queue_depth"]) if item["queue_depth"] > 0 else c_dim("idle")
# Format title/URL nicely
title = item["title"]
if item.get("approval_pending"):
target = item.get("approval_detail", {}).get("ip") or "request"
title = f"{c_yellow('[APPROVAL: ' + target + ']')} {title}"
elif "thread/" in item["url"]:
m = re.search(r"thread/([0-9a-fA-F-]+)", item["url"])
if m:
uuid_short = m.group(1)[:8]
title = f"{title} [{c_cyan(uuid_short)}]"
elif item["url"] == "https://muse.ai/":
title = f"{title} [{c_dim('home')}]"
rows.append([
c_bold(item["node"]),
status,
f"{item['peer_ip']}:{item['cdp_port']}",
lat,
q,
title[:50]
])
print_table(headers, rows)
if any(r.get("source") == "host-evidence" for r in data):
print(c_dim(" [*] status via host watchdog evidence (local probes blind in this shell)"))
if has_any_approval:
print("\n" + c_yellow(" ⚠ Agent(s) held up on browser approval. Run 'box approvals' to inspect/allow."))
print("\n" + c_dim(" Commands: super fleet watch | super fleet heal <node> | box approvals [check|allow|auto]") + "\n")
def cmd_fleet_watch(args):
interval = getattr(args, "interval", 2)
try:
while True:
# Clear terminal
sys.stdout.write("\033[2J\033[H")
sys.stdout.flush()
cmd_fleet_status(args)
print(c_dim(f" [Auto-refreshing every {interval}s. Press Ctrl+C to exit]"))
time.sleep(interval)
except KeyboardInterrupt:
print("\n" + c_dim("Exited watch mode."))
def cmd_fleet_restart(args):
node = args.node
if node not in VALID_NODES:
print(f"Error: Unknown node '{node}'. Valid: {', '.join(VALID_NODES)}", file=sys.stderr)
sys.exit(1)
print(f"Restarting node '{c_bold(node)}' via netvm-node-up.sh...")
cmd = ["sudo", str(BIN_DIR / "netvm-node-up.sh"), node]
res = subprocess.run(cmd, text=True)
if res.returncode == 0:
print(c_green(f"Node '{node}' brought up successfully."))
else:
print(c_red(f"Node restart exited with code {res.returncode}."))
sys.exit(res.returncode)
def cmd_fleet_cdp(args):
node = args.node
if node not in VALID_NODES:
print(f"Error: Unknown node '{node}'", file=sys.stderr)
sys.exit(1)
info = get_node_network_info(node)
peer = info["peer_ip"]
port = info["cdp_port"]
if args.json:
print(json.dumps({
"node": node,
"peer_ip": peer,
"port": port,
"url": f"http://{peer}:{port}",
"ssh_forward": f"ssh -L {port}:{peer}:{port} super@100.123.153.75"
}, indent=2))
return
print(f"\n{c_bold('CDP Access for ' + node)}:")
print(f" Host Endpoint : {c_cyan(f'http://{peer}:{port}/json/version')}")
print(f" SSH Forward : {c_yellow(f'ssh -L {port}:{peer}:{port} super@100.123.153.75')}")
print(f" Local Connect : {c_dim(f'http://127.0.0.1:{port}')} (after forwarding)\n")
# ---------------------------------------------------------------------------
# Domain: FLEET HEAL + WATCHDOG
# ---------------------------------------------------------------------------
SYSTEMD_SYSTEM_DIR = Path("/etc/systemd/system")
WATCHDOG_LOCK_TMPL = "/tmp/chromebox-watchdog-{node}.lock"
WARP_PROBE_URL = "https://1.1.1.1/cdn-cgi/trace"
CHROMEBOX_TIMER_TMPL = """[Unit]
Description=Run chromebox watchdog for {node} every 2 minutes
[Timer]
RandomizedDelaySec=30s
OnBootSec=2min
OnUnitActiveSec=2min
Unit=chromebox-watchdog@{node}.service
[Install]
WantedBy=timers.target
"""
def _sh(cmd, timeout=120, input_text=None):
"""Run cmd, capture output. Returns (returncode, combined_output)."""
try:
r = subprocess.run(cmd, capture_output=True, text=True,
timeout=timeout, input=input_text)
return r.returncode, ((r.stdout or "") + (r.stderr or "")).strip()
except subprocess.TimeoutExpired:
return 124, "timed out after %ds: %s" % (timeout, " ".join(cmd))
except OSError as e:
return 127, str(e)
def _heal_lock_step(node):
"""Clear a stale unwritable watchdog lock (blocks watchdog startup)."""
lock = Path(WATCHDOG_LOCK_TMPL.format(node=node))
if not lock.exists() or os.access(lock, os.W_OK):
return True, "lock writable or absent"
rc, out = _sh(["sudo", "rm", "-f", str(lock)], timeout=30)
if rc == 0:
return True, "removed stale lock %s" % lock
return False, "cannot remove %s: %s" % (lock, out)
def _heal_timer_step(node):
"""Install (if missing) and enable the node's watchdog timer."""
timer = "chromebox-watchdog-%s.timer" % node
path = SYSTEMD_SYSTEM_DIR / timer
if not path.exists():
rc, out = _sh(["sudo", "tee", str(path)], timeout=30,
input_text=CHROMEBOX_TIMER_TMPL.format(node=node))
if rc != 0:
return False, "cannot install %s: %s" % (timer, out)
rc, out = _sh(["sudo", "systemctl", "daemon-reload"], timeout=60)
if rc != 0:
return False, "daemon-reload failed: %s" % out
rc, out = _sh(["sudo", "systemctl", "enable", "--now", timer], timeout=60)
if rc != 0:
return False, "enable --now failed: %s" % out
return True, "timer installed+active"
def _heal_tunnel_step(node):
"""Restart the node's Warp tunnel + CDP relay via netvm-node-up.sh."""
rc, out = _sh(["sudo", str(BIN_DIR / "netvm-node-up.sh"), node], timeout=240)
last = out.strip().splitlines()[-1] if out.strip() else "(no output)"
if rc != 0:
return False, "netvm-node-up.sh rc=%d: %s" % (rc, last)
if "egress=unknown" in out or "no handshake yet" in out:
return False, last
return True, last
def _warp_egress_ok(node):
"""True when the node's netns reaches the warp probe URL."""
rc, out = _sh(["sudo", "ip", "netns", "exec", "warp-%s" % node,
"curl", "-sk", "--max-time", "10", WARP_PROBE_URL],
timeout=30)
if rc != 0:
tail = out.splitlines()[-1] if out else "curl failed"
return False, tail
for line in out.splitlines():
if line.startswith("ip="):
return True, line
return False, "no ip= line in probe response"
def cmd_fleet_heal(args):
node = args.node
if node not in VALID_NODES:
print(f"Error: Unknown node '{node}'. Valid: {', '.join(VALID_NODES)}", file=sys.stderr)
sys.exit(1)
as_json = getattr(args, "json", False)
info = get_node_network_info(node)
steps = []
def record(step, ok, detail):
steps.append({"step": step, "ok": ok, "detail": detail})
if not as_json:
mark = c_green("ok") if ok else c_red("FAIL")
print(f" [{mark}] {step}: {detail}")
if not as_json:
print(f"\n{c_bold('Healing node ' + node)} ({info['netns']}, {info['peer_ip']}:{info['cdp_port']})")
record("lock", *_heal_lock_step(node))
record("timer", *_heal_timer_step(node))
record("tunnel", *_heal_tunnel_step(node))
egress_ok, egress_detail = _warp_egress_ok(node)
record("egress", egress_ok, egress_detail)
relay = probe_cdp_status(info["peer_ip"], info["cdp_port"])
if relay["ok"]:
record("relay", True, "CDP answers in %sms" % relay["latency_ms"])
else:
record("relay", False, relay.get("error", "unreachable"))
verdict = "RECOVERED" if egress_ok else "DOWN"
if as_json:
print(json.dumps({"ok": egress_ok, "node": node,
"verdict": verdict, "steps": steps}, indent=2))
else:
print(f"\n Verdict: {c_green(verdict) if egress_ok else c_red(verdict)}")
if not egress_ok:
print(c_dim(" Tunnel still down after restart — if it persists, the Warp identity "
f"likely needs regenerating (human: netvm-new-identity.sh {node})"))
print()
sys.exit(0 if egress_ok else 1)
def _unit_state(unit):
"""(enabled, active) booleans for a systemd unit."""
rc_e, _ = _sh(["systemctl", "is-enabled", unit], timeout=15)
rc_a, _ = _sh(["systemctl", "is-active", unit], timeout=15)
return rc_e == 0, rc_a == 0
def cmd_watchdog_status(args):
as_json = getattr(args, "json", False)
try:
import host_evidence
ev = host_evidence.collect()
except Exception:
ev = {}
data = []
for node in VALID_NODES:
timer = "chromebox-watchdog-%s.timer" % node
enabled, active = _unit_state(timer)
node_ev = ev.get(node, {})
data.append({
"node": node,
"timer": timer,
"enabled": enabled,
"active": active,
"browser": node_ev.get("browser", "unknown"),
"browser_detail": node_ev.get("browser_detail", ""),
"cdp": node_ev.get("cdp", "unknown"),
"cdp_detail": node_ev.get("cdp_detail", ""),
})
relay_enabled, relay_active = _unit_state("cdp-relay-watchdog.timer")
relay = {"timer": "cdp-relay-watchdog.timer",
"enabled": relay_enabled, "active": relay_active}
if as_json:
print(json.dumps({"ok": True, "nodes": data, "relay": relay}, indent=2))
return
print("\n" + c_bold("=== WATCHDOG STATUS ===") + c_dim(f" ({datetime.now().strftime('%H:%M:%S')} local)\n"))
headers = ["NODE", "TIMER", "BROWSER", "CDP"]
rows = []
for item in data:
timer = badge_ok("active") if item["active"] else (
badge_warn("ENABLED") if item["enabled"] else badge_dim("missing"))
rows.append([c_bold(item["node"]), timer,
item["browser"], item["cdp"]])
print_table(headers, rows)
rmark = badge_ok("active") if relay["active"] else badge_dim("missing")
print(f" relay: {rmark} {c_dim('cdp-relay-watchdog.timer')}\n")
def cmd_watchdog_run(args):
target = args.target
as_json = getattr(args, "json", False)
if target == "relay":
unit = "cdp-relay-watchdog.service"
elif target in VALID_NODES:
unit = "chromebox-watchdog@%s.service" % target
else:
print("Error: Specify node or 'relay' (e.g. box watchdog run dev)", file=sys.stderr)
sys.exit(1)
rc, out = _sh(["sudo", "systemctl", "start", unit], timeout=180)
tail = out[-500:] if out else ""
if as_json:
print(json.dumps({"ok": rc == 0, "unit": unit, "detail": tail}, indent=2))
else:
if rc == 0:
print(c_green(f"Watchdog run triggered: {unit}"))
else:
print(c_red(f"Failed to start {unit}: {tail}"))
sys.exit(0 if rc == 0 else 1)
# ---------------------------------------------------------------------------
# Domain: APPROVALS
# ---------------------------------------------------------------------------
def cmd_approvals(args):
import approvals
action = getattr(args, "app_action", None) or "check"
node = getattr(args, "node", None)
if action in ("check", "list", "inspect"):
nodes = [node] if node else VALID_NODES
fleet = approvals.check_fleet_approvals(nodes)
if getattr(args, "json", False):
print(json.dumps({"ok": True, "approvals": fleet}, indent=2))
return
print("\n" + c_bold("=== FLEET APPROVALS STATUS ===") + c_dim(f" ({datetime.now().strftime('%H:%M:%S')} local)\n"))
headers = ["NODE", "STATUS", "TARGET / IP", "PURPOSE / DETAILS", "TRUST", "ACTIONS"]
rows = []
pending_count = 0
untrusted_count = 0
input_wait_count = 0
for it in fleet:
n = it["node"]
st = it["status"]
if st == "PENDING":
pending_count += 1
badge = badge_err("PENDING") if not it.get("is_trusted") else badge_warn("PENDING")
target = it.get("target") or it.get("ip") or "-"
purp = (it.get("purpose") or it.get("title") or "-")[:50]
trust = c_green("TRUSTED") if it.get("is_trusted") else c_red("UNTRUSTED")
btns = " ".join([f"[{b}]" for b in it.get("buttons", [])])
if not it.get("is_trusted"):
untrusted_count += 1
elif st == "KEY_APPROVAL":
pending_count += 1
badge = badge_warn("KEY_REQ")
target = it.get("target") or "VM passkey"
purp = (it.get("purpose") or it.get("title") or "-")[:50]
trust = c_cyan("OPERATOR")
btns = " ".join([f"[{b}]" for b in it.get("buttons", ["Allow", "Deny"])])
untrusted_count += 1
elif st == "INPUT_WAIT":
waits = it.get("input_waits") or []
badge = badge_warn("INPUT")
target = "-"
purp = "; ".join(f"{w.get('task')}: {w.get('status')}" for w in waits)[:60]
trust = "-"
btns = c_dim("answer in task")
input_wait_count += 1
elif st == "UNREACHABLE":
if it.get("host_cdp_ok") is True:
badge = badge_dim("BLIND")
purp = c_dim("CDP ok on host; blind here")
elif it.get("host_cdp_ok") is False:
badge = badge_err("OFFLINE")
purp = c_dim("CDP down (host agrees)")
else:
badge = badge_dim("OFFLINE")
purp = c_dim("CDP unreachable")
target = "-"
trust = "-"
btns = "-"
elif st == "ERROR":
badge = badge_err("ERROR")
target = "-"
purp = it.get("error", "-")[:40]
trust = "-"
btns = "-"
else:
badge = badge_ok("CLEAR")
target = "-"
purp = c_dim("No pending approvals")
trust = "-"
btns = "-"
rows.append([c_bold(n), badge, target, purp, trust, btns])
print_table(headers, rows)
if input_wait_count > 0:
print("\n" + c_yellow(f" ⚠ {input_wait_count} node(s) have tasks waiting for human input (not auto-resolvable)."))
if pending_count > 0:
print("\n" + c_yellow(f" ⚠ {pending_count} pending approval(s) detected across fleet."))
if untrusted_count > 0:
print(c_red(f" ⚠ {untrusted_count} approval(s) require manual review / key grant: 'box approvals allow <node>' or 'box approvals deny <node>'."))
else:
print(c_cyan(" All pending approvals are for trusted infrastructure. Run 'box approvals auto' to resolve."))
print()
elif input_wait_count == 0:
unreach = [it for it in fleet if it.get("status") == "UNREACHABLE"]
blind_ok = [it["node"] for it in unreach
if it.get("host_cdp_ok") is True]
blind_unknown = [it["node"] for it in unreach
if it.get("host_cdp_ok") is None]
if blind_ok:
print("\n" + c_dim(" ? %d node(s) blind from this shell "
"(CDP ok on host); queues unverified: %s."
% (len(blind_ok), ", ".join(blind_ok))) + "\n")
if blind_unknown:
print("\n" + c_dim(" ? %d node(s) unreachable, host evidence "
"inconclusive: %s."
% (len(blind_unknown),
", ".join(blind_unknown))) + "\n")
if not blind_ok and not blind_unknown:
print("\n" + c_green(" ✔ All agent approval queues clear. No agents blocked.") + "\n")
# Verbose or inspect breakdown
is_verbose = getattr(args, "verbose", False) or action == "inspect"
if is_verbose:
print(c_bold("\n=== DETAILED NODE INSPECTION ==="))
for it in fleet:
n = it["node"]
if it.get("has_pending") or it.get("input_waits") or action == "inspect":
print(f"\n [{c_bold(n)}] Status: {it.get('status')} | Page: {c_cyan(it.get('page_url') or '-')}")
if it.get("has_pending"):
print(f" Egress Target: {it.get('target') or it.get('ip')} ({'TRUSTED' if it.get('is_trusted') else 'UNTRUSTED'})")
print(f" Prompt Title : {it.get('title')}")
if it.get("purpose"):
print(f" Purpose : {it.get('purpose')}")
print(f" Buttons : {', '.join(it.get('buttons') or [])}")
if it.get("input_waits"):
print(f" Tasks Awaiting Human Input ({len(it['input_waits'])}):")
for w in it["input_waits"]:
print(f" • {c_bold(w.get('task'))}")
print(f" Status: {w.get('status')} ({w.get('when')})")
# Correlate with active subagents on this node
try:
import subagent_tracker
active_subs = subagent_tracker.get_active_sessions(n)
if active_subs:
print(f" Active Subagents on Node ({len(active_subs)}):")
for sub in active_subs[-3:]:
s_id = sub.get("session_id", "")[:8]
s_title = sub.get("title") or "subagent"
print(f" • [{s_id}] {c_bold(s_title)} (spawned: {sub.get('spawned_at', '-')})")
except Exception:
pass
print()
elif action in ("allow", "approve"):
if not node:
print(c_red("Error: Must specify node for allow. e.g. 'box approvals allow 646'"), file=sys.stderr)
sys.exit(1)
always = getattr(args, "always", False)
force = getattr(args, "force", False)
message = getattr(args, "message", None)
allow_main_chat = getattr(args, "allow_main_chat", False)
res = approvals.allow_node_approval(node, always=always, force=force, message=message,
allow_main_chat=allow_main_chat)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
if res.get("ok"):
if res.get("type") == "key_approval":
notified = "agent notified" if res.get("notified") else "⚠ agent NOT notified (follow up manually)"
print(c_green(f"✔ Approved operator key request for node '{node}'. Logged to audit trail. {notified}."))
else:
decision_str = "Always allow this site" if always else "Allow once"
print(c_green(f"✔ Approved request on node '{node}' ({decision_str}). Dialog dismissed: {res.get('dismissed')}."))
else:
print(c_red(f"✖ Failed to approve on node '{node}': {res.get('error')}"))
sys.exit(2 if "Untrusted" in res.get("error", "") else 1)
elif action == "deny":
if not node:
print(c_red("Error: Must specify node for deny. e.g. 'box approvals deny 646'"), file=sys.stderr)
sys.exit(1)
message = getattr(args, "message", None)
allow_main_chat = getattr(args, "allow_main_chat", False)
res = approvals.deny_node_approval(node, message=message, allow_main_chat=allow_main_chat)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
if res.get("ok"):
if res.get("type") == "key_approval":
notified = "agent notified" if res.get("notified") else "⚠ agent NOT notified (follow up manually)"
print(c_green(f"✔ Denied operator key request for node '{node}'. Logged to audit trail. {notified}."))
else:
print(c_green(f"✔ Denied request on node '{node}'. Dialog dismissed: {res.get('dismissed')}."))
else:
print(c_red(f"✖ Failed to deny on node '{node}': {res.get('error')}"))
sys.exit(1)
elif action == "auto":
nodes = [node] if node else VALID_NODES
res = approvals.auto_approve_fleet(nodes)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
approved = res.get("auto_approved", [])
untrusted = res.get("untrusted_pending", [])
if approved:
print("\n" + c_green(f"✔ Auto-approved {len(approved)} trusted request(s):"))
for a in approved:
print(f" • {c_bold(a['node'])}: {a.get('target_ip')} — {a.get('title')}")
if untrusted:
print("\n" + c_yellow(f"⚠ {len(untrusted)} untrusted request(s) require manual decision:"))
for u in untrusted:
print(f" • {c_bold(u['node'])}: {u.get('ip')} — {u.get('title')} (run: box approvals allow {u['node']} --force)")
if not approved and not untrusted:
print(c_green("✔ All nodes clear. No approvals pending."))
print()
if untrusted:
sys.exit(2)
elif action == "watch":
interval = getattr(args, "interval", 2)
auto_mode = getattr(args, "auto", False)
try:
while True:
sys.stdout.write("\033[2J\033[H")
sys.stdout.flush()
if auto_mode:
auto_res = approvals.auto_approve_fleet(nodes=[node] if node else VALID_NODES)
if auto_res.get("auto_approved"):
for a in auto_res["auto_approved"]:
print(c_green(f"[AUTO-APPROVED] {a['node']}: {a.get('target_ip')}"))
# Print status
setattr(args, "app_action", "check")
cmd_approvals(args)
auto_label = c_cyan(" [AUTO-APPROVE ENABLED]") if auto_mode else ""
print(c_dim(f" [Watching every {interval}s{auto_label}. Press Ctrl+C to exit]"))
time.sleep(interval)
except KeyboardInterrupt:
print("\n" + c_dim("Exited watch mode."))
elif action == "reply":
if not node:
print(c_red("Error: Must specify node for reply. e.g. 'box approvals reply pip \"proceed\"'"), file=sys.stderr)
sys.exit(1)
message = getattr(args, "message", "")
allow_main = getattr(args, "allow_main_chat", False)
res = approvals.reply_node_task(node, message, allow_main_chat=allow_main)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
if res.get("ok"):
print(c_green(f"✔ Dispatched reply to node '{node}': \"{message}\" (thread: {res.get('page_url')})"))
else:
print(c_red(f"✖ Failed to reply to node '{node}': {res.get('error')}"))
sys.exit(2 if "Main Chat" in res.get("error", "") else 1)
elif action == "dismiss":
if not node:
print(c_red("Error: Must specify node for dismiss. e.g. 'box approvals dismiss pip'"), file=sys.stderr)
sys.exit(1)
res = approvals.dismiss_node_task(node)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
if res.get("ok"):
print(c_green(f"✔ Dismissed task popup on node '{node}' ({res.get('result')})."))
else:
print(c_red(f"✖ Failed to dismiss task popup on node '{node}': {res.get('error')}"))
sys.exit(1)
elif action in ("clear", "clear-all", "clear_all"):
target_node = node
if action in ("clear-all", "clear_all"):
target_node = None
res = approvals.clear_node_waits(target_node)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
cleared = res.get("total_cleared", 0)
target_desc = f"node '{target_node}'" if target_node else "all fleet nodes"
print(c_green(f"✔ Cleared {cleared} input wait(s) on {target_desc}."))
elif action in ("request-key", "request_key"):
if not node:
print(c_red("Error: Must specify node for request-key. e.g. 'box approvals request-key 646'"), file=sys.stderr)
sys.exit(1)
reason = getattr(args, "reason", "Operator passkey access requested")
caller = os.environ.get("BOX_CALLER") or getattr(args, "from_agent", "super")
res = approvals.request_key_approval(node, reason=reason, caller=caller)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
print(c_green(f"✔ Registered passkey approval request for node '{node}'."))
print(f" Reason: {c_cyan(reason)}")
print(c_dim(f" Operator can approve with: box approvals allow {node}"))
elif action in ("gates", "gate"):
scope = getattr(args, "scope", None)
if scope:
res = approvals.verify_coordinator_signoff(scope)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
return
if res.get("ok"):
print(c_green(f"\n✔ Coordinator gate for scope '{scope}' is SIGNED-OFF."))
print(f" Coordinator: {c_cyan(res.get('coordinator'))}")
print(f" Accepted At: {c_dim(res.get('accepted_at'))}")
print(f" Record: {res.get('doc_name')}\n")
else:
print(c_red(f"\n✖ Coordinator gate verification FAILED for scope '{scope}':"))
print(f" Error: {res.get('error')}\n")
sys.exit(1)
return
gates = approvals.scan_coordinator_gates()
if getattr(args, "json", False):
print(json.dumps({"ok": True, "gates": gates}, indent=2))
return
print("\n" + c_bold("=== COORDINATOR GATES & DECISION RECORDS ===\n"))
if not gates:
print(c_dim(" (no coordinator decision records found in docs/)"))
print()
return
headers = ["RECORD", "SCOPE", "STATUS", "COORDINATOR", "ACCEPTED AT", "TARGETS"]
rows = []
for g in gates:
st = c_green("SIGNED-OFF") if g.get("is_signed_off") else c_yellow(str(g.get("status", "DRAFT")).upper())
targets = ", ".join(g.get("signoff_targets") or []) if isinstance(g.get("signoff_targets"), list) else str(g.get("signoff_targets") or "-")
rows.append([
g.get("doc_name", "-"),
c_cyan(g.get("scope", "-")),
st,
g.get("coordinator", "-"),
str(g.get("accepted_at", "-"))[:19],
targets or "-",
])
print_table(headers, rows)
print()
# ---------------------------------------------------------------------------
# Domain: RUNTIME (agentic management of Muse CLI tmux runtimes)
# ---------------------------------------------------------------------------
def cmd_runtime(args):
import shlex
import muse_choice_watcher as mcw
action = getattr(args, "rt_action", None) or "list"
as_json = getattr(args, "json", False)
if getattr(args, "socket", None):
args.socket = mcw.resolve_socket(args.socket)
if action == "list":
sock = getattr(args, "socket", None)
errors = {}
rows = mcw.all_runtime_rows([sock] if sock else None, errors=errors)
if getattr(args, "muse_only", False):
rows = [r for r in rows if r["is_muse"]]
if as_json:
print(json.dumps({"ok": True, "runtimes": rows,
"errors": errors}, indent=2))
return
print(c_bold("\n=== MUSE RUNTIMES ===\n"))
if not rows:
print(c_dim(" No panes found."))
for s, e in errors.items():
print(c_dim(" %s: %s" % (s, e)))
print()
return
headers = ["SOCKET", "SESSION", "NODE", "PANE", "CMD",
"STATE", "APPROVE", "MODE", "WATCHER"]
table = []
for r in rows:
state = r["state"]
if r["state"] == "approval-pending" and r["prompt_kind"]:
state = "%s(%s/%s)" % (state, r["prompt_kind"],
r["prompt_key"] or "…")
if r["is_muse"]:
eff_bypass = r.get("effective_bypass")
if eff_bypass is None:
eff_bypass = bool(r["auto_approve"])
approve = (badge_ok("YES") if eff_bypass
else badge_err("NO"))
mode = (r.get("effective_mode")
or r.get("permission_mode") or "default")
if eff_bypass and mode != "yolo":
mode += "!"
mode = mode[:14]
else:
approve = badge_dim("-")
mode = badge_dim("-")
watcher = (badge_ok("ALIVE %s" % r["watcher_pid"])
if r["watcher_alive"] else badge_dim("-"))
table.append([os.path.basename(r["socket"]),
"%s:%s" % (r["session"], r["window"]),
r["node"] or badge_dim("-"),
r["pane"], (r["cmd"] or "")[:26], state,
approve, mode, watcher])
print_table(headers, table)
for s, e in errors.items():
print(c_dim(" %s: %s" % (s, e)))
print()
elif action == "send":
sock = getattr(args, "socket", None) or mcw.KNOWN_SOCKETS[0]
pane = args.pane
keys = args.keys
enter = not getattr(args, "no_enter", False)
pre = mcw.pane_state(sock, pane)
if pre.get("error"):
if as_json:
print(json.dumps({"ok": False, "error": pre["error"],
"socket": sock, "pane": pane,
"detail": pre.get("detail")}))
return
if pre["error"] == "socket_unreachable":
print(c_red("Error: cannot reach socket %s: %s"
% (sock, pre.get("detail") or "tmux error")),
file=sys.stderr)
else:
print(c_red("Error: no such pane %s on %s" % (pane, sock)),
file=sys.stderr)
sys.exit(1)
# Verified send: keys + Enter in one tmux call arrive as a paste
# burst, which the muse composer takes as a newline instead of a
# submit. send_answer paces literal text and Enter apart (with a
# render check for composer-bound prompts) so the submit lands.
ok, detail = mcw.send_answer(sock, pane, keys, enter=enter,
kind=pre.get("prompt_kind"), sig=None)
if as_json:
print(json.dumps({
"ok": ok, "socket": sock, "pane": pane,
"pre_state": pre["state"],
"prompt_kind": pre["prompt_kind"],
"sent": keys, "enter": enter,
"verified": detail["verified"],
"retried": detail["retried"],
"error": None if ok else "tmux error"}, indent=2))
return
print("\n Pane %s on %s [%s]" % (
c_bold(pane), sock, c_cyan(pre["state"])))
if ok:
how = " (verified)" if detail["verified"] else ""
print(" %s sent %r%s%s" % (c_green("✔"), keys,
" + Enter" if enter else "", how))
else:
print(" %s send failed: %s" % (c_red("✘"), "tmux error"))
sys.exit(1)
print()
elif action == "open":
sock = getattr(args, "socket", None) or mcw.KNOWN_SOCKETS[0]
session = getattr(args, "session", None)
dry_run = getattr(args, "dry_run", False)
def _fail_open(msg, candidates=None):
if as_json:
print(json.dumps({"ok": False, "error": msg,
"socket": sock, "session": session,
"sessions": candidates or []}))
return
print(c_red("Error: %s" % msg), file=sys.stderr)
if candidates:
print(" Sessions on %s: %s" % (sock, ", ".join(candidates)),
file=sys.stderr)
sys.exit(1)
def _sessions():
r = mcw._tmux(sock, "list-sessions", "-F", "#{session_name}",
timeout=10)
if r.returncode != 0:
return []
return [ln.strip() for ln in (r.stdout or "").split("\n")
if ln.strip()]
if not os.path.exists(sock):
_fail_open("no such socket %s" % sock)
return
if not session:
names = _sessions()
if len(names) == 1:
session = names[0]
else:
_fail_open("no session given and %s on %s"
% ("no sessions found" if not names
else "multiple sessions", sock), names)
return
else:
probe = mcw._tmux(sock, "has-session", "-t", session,
timeout=10)
if probe.returncode != 0:
_fail_open("no such session %s on %s" % (session, sock),
_sessions())
return
argv = ["tmux", "-S", sock, "attach-session", "-t", session]
if dry_run or as_json:
if as_json:
print(json.dumps({"ok": True, "dry_run": bool(dry_run),
"socket": sock, "session": session,
"argv": argv}, indent=2))
return
print(c_bold("\n=== RUNTIME OPEN (dry-run) ===\n"))
print(" Socket: %s" % sock)
print(" Session: %s" % c_cyan(session))
print(" Command: %s" % shlex.join(argv))
print()
return
try:
os.execvp("tmux", argv)
except OSError as e:
print(c_red("Error: cannot exec tmux: %s" % e),
file=sys.stderr)
sys.exit(1)
elif action == "launch":
sock = getattr(args, "socket", None) or mcw.FLEET_SOCKETS[0]
# Track box-launched session
try:
box_state_file = NETVM_ROOT / ".state" / "box-launched-sessions.json"
box_state_file.parent.mkdir(parents=True, exist_ok=True)
box_data = {}
if box_state_file.exists():
box_data = json.loads(box_state_file.read_text())
box_data[args.session] = {"socket": sock, "launched_at": datetime.now(timezone.utc).isoformat(), "origin": "box-cli"}
box_state_file.write_text(json.dumps(box_data, indent=2))
except Exception:
pass
session = args.session
window = getattr(args, "window", None)
dry_run = getattr(args, "dry_run", False)
muse_args = list(getattr(args, "muse_args", None) or [])
cmdline, injected = mcw.muse_launch_cmdline(muse_args)
if dry_run:
if as_json:
print(json.dumps({
"ok": True, "dry_run": True, "socket": sock,
"session": session, "window": window,
"cmdline": cmdline, "injected": injected}, indent=2))
return
print(c_bold("\n=== RUNTIME LAUNCH (dry-run) ===\n"))
print(" Socket: %s" % sock)
print(" Session: %s" % c_cyan(session))
print(" Command: %s" % cmdline)
if injected:
print(" %s approval trail injected: %s" % (
c_green("✔"), " ".join(injected)))
else:
print(" %s caller already sets approval flags; "
"nothing injected" % c_dim("•"))
print()
return
exists = mcw._tmux(sock, "has-session", "-t", session, timeout=10)
if exists.returncode == 0:
if as_json:
print(json.dumps({"ok": False, "error": "session_exists",
"socket": sock, "session": session}))
return
print(c_red("Error: session '%s' already exists on %s"
% (session, sock)), file=sys.stderr)
sys.exit(1)
t_args = ["new-session", "-d", "-s", session]
if window:
t_args.extend(["-n", window])
t_args.append(cmdline)
r = mcw._tmux(sock, *t_args, timeout=15)
if r.returncode != 0:
err = (r.stderr or r.stdout or "").strip() or "tmux error"
if as_json:
print(json.dumps({"ok": False, "error": err,
"socket": sock, "session": session}))
return
print(c_red("Error: launch failed: %s" % err),
file=sys.stderr)
sys.exit(1)
mcw.wait_for_session_pane(sock, session, timeout=10)
rec = mcw.reconcile(sockets=[sock])
if as_json:
print(json.dumps({"ok": True, "socket": sock,
"session": session, "window": window,
"cmdline": cmdline, "injected": injected,
"reconcile": rec}, indent=2))
return
print(c_green("\n✔ Launched '%s' on %s") % (session, sock))
print(" Command: %s" % c_dim(cmdline))
for s in rec.get("started") or []:
print(" %s watcher %s" % (badge_ok("STARTED"), c_cyan(s)))
for f in rec.get("failed") or []:
print(" %s watcher %s (retry: box muse-choices reconcile)"
% (badge_err("FAILED"), c_cyan(f)))
print()
elif action == "layout":
sock = getattr(args, "socket", None)
rows = mcw.all_runtime_rows([sock] if sock else None)
minimum = {"width": mcw.MIN_APPROVAL_WIDTH,
"height": mcw.MIN_APPROVAL_HEIGHT}
if as_json:
print(json.dumps({"ok": True, "runtimes": rows,
"minimum": minimum}, indent=2))
return
print(c_bold("\n=== RUNTIME LAYOUT ===\n"))
print(c_dim(" Minimum for reliable approvals: %dx%d\n" % (
minimum["width"], minimum["height"])))
if not rows:
print(c_dim(" No panes found."))
print()
return
headers = ["SOCKET", "SESSION", "PANE", "DIMS", "GEO", "CMD"]
table = []
for r in rows:
dims = ("%dx%d" % (r["width"], r["height"])
if r["width"] is not None else "-")
if not r["is_muse"]:
geo = badge_dim("-")
elif r["squeezed"]:
geo = badge_err("SQUEEZED")
else:
geo = badge_ok("OK")
table.append([os.path.basename(r["socket"]),
"%s:%s" % (r["session"], r["window"]),
r["pane"], dims, geo, (r["cmd"] or "")[:26]])
print_table(headers, table)
targets = mcw.spread_targets(rows)
if targets:
print(c_yellow(" %d squeezed runtime(s): %s" % (
len(targets), ", ".join(
"%s:%s" % (t["session"], t["pane"])
for t in targets))))
print(c_dim(" Run `box runtime spread` to break them into "
"own windows."))
print()
elif action == "spread":
sock = getattr(args, "socket", None)
session = getattr(args, "session", None)
dry_run = getattr(args, "dry_run", False)
rows = mcw.all_runtime_rows([sock] if sock else None)
if session:
rows = [r for r in rows if r["session"] == session]
targets = mcw.spread_targets(rows)
if dry_run:
if as_json:
print(json.dumps({"ok": True, "dry_run": True,
"targets": targets}, indent=2))
return
print(c_bold("\n=== RUNTIME SPREAD (dry-run) ===\n"))
if not targets:
print(c_dim(" No squeezed runtimes; nothing to spread."))
for t in targets:
print(" Would break %s %s:%s (%dx%d) into own "
"window" % (t["socket"], t["session"], t["pane"],
t["width"], t["height"]))
print()
return
spread, failed = [], []
for t in targets:
name = "spread-%s" % t["pane"]
# -t session: pins the new window to the SOURCE session.
# Without it break-pane follows the ATTACHED session and
# flings panes across sessions (observed live on scratch).
r = mcw._tmux(t["socket"], "break-pane", "-s", t["pane"],
"-t", "%s:" % t["session"], "-n", name,
timeout=15)
if r.returncode == 0:
spread.append("%s:%s" % (t["session"], t["pane"]))
else:
failed.append({
"pane": "%s:%s" % (t["session"], t["pane"]),
"error": (r.stderr or r.stdout or "").strip()
or "tmux error"})
if as_json:
print(json.dumps({"ok": not failed, "spread": spread,
"failed": failed}, indent=2))
return
print(c_bold("\n=== RUNTIME SPREAD ===\n"))
if not targets:
print(c_dim(" No squeezed runtimes; nothing to spread."))
for s in spread:
print(" %s spread %s (watchers follow pane ids)" % (
badge_ok("MOVED"), c_cyan(s)))
for f in failed:
print(" %s %s: %s" % (
badge_err("FAILED"), f["pane"], f["error"]))
print()
elif action == "reconcile":
import runtime_reconcile as rec
manifest = (getattr(args, "manifest", None)
or str(NETVM_ROOT / "fleet" / "agents.json"))
tasks = getattr(args, "tasks", None)
dry_run = getattr(args, "dry_run", False)
adopt = getattr(args, "adopt", False)
report = rec.run_reconcile(manifest, tasks_dir=tasks,
dry_run=dry_run, adopt=adopt)
if as_json:
print(json.dumps(report, indent=2))
return
print(c_bold("\n=== RUNTIME RECONCILE%s ===\n" % (
" (dry-run)" if dry_run else "")))
if not report["agents"] and not report["errors"]:
print(c_dim(" Manifest declares no agents."))
for a in report["agents"]:
if a["action"] in ("launched", "briefed", "adopted"):
mark = badge_ok(a["action"].upper())
elif a["action"] in ("failed",):
mark = badge_err("FAILED")
elif a["action"] in ("launch", "brief"):
mark = c_cyan("WOULD " + a["action"].upper())
else:
mark = c_dim("• " + a["action"])
print(" %s %s [%s]: %s" % (
mark, c_cyan(a["session"]), a["hat"], a["detail"]))
for c in report["claims"]["requeued"]:
print(" %s task %s (%s)" % (
badge_ok("REQUEUED"), c_cyan(c["task"]), c["reason"]))
for n in report.get("nudges") or []:
print(" %s %s nudge to %s: %s" % (
badge_ok("NUDGED"), n["kind"],
c_cyan(n["session"]), n["detail"]))
for e in report["claims"]["errors"] + report["errors"]:
print(" %s %s" % (badge_err("ERROR"), e))
w = report.get("watchers") or {}
if w.get("started"):
print(" %s watchers: %s" % (
badge_ok("STARTED"), ", ".join(w["started"])))
print()
if not report["ok"]:
sys.exit(1)
elif action == "kill":
import runtime_reconcile as rec
sock = getattr(args, "socket", None) or mcw.KNOWN_SOCKETS[0]
session = args.session
err = rec.kill_session(sock, session)
if as_json:
print(json.dumps({"ok": err is None, "socket": sock,
"session": session,
"error": err}, indent=2))
return
if err is None:
print(c_green("\n✔ Killed '%s' on %s\n") % (session, sock))
return
print(c_red("Error: cannot kill '%s' on %s: %s"
% (session, sock, err)), file=sys.stderr)
sys.exit(1)
elif action == "restart":
import runtime_reconcile as rec
sock = getattr(args, "socket", None) or mcw.KNOWN_SOCKETS[0]
session = args.session
manifest = (getattr(args, "manifest", None)
or str(NETVM_ROOT / "fleet" / "agents.json"))
dry_run = getattr(args, "dry_run", False)
res = rec.restart_agent(manifest, sock, session, dry_run=dry_run)
ok = res["action"] in ("restarted", "restart")
if as_json:
print(json.dumps({"ok": ok, "socket": sock,
"session": session,
"action": res["action"],
"detail": res["detail"]}, indent=2))
return
if ok:
print(c_green("\n✔ %s '%s': %s\n")
% ("Restarted" if res["action"] == "restarted"
else "Would restart", session, res["detail"]))
return
print(c_red("Error: cannot restart '%s': %s"
% (session, res["detail"])), file=sys.stderr)
sys.exit(1)
elif action == "brief":
import runtime_reconcile as rec
sock = getattr(args, "socket", None) or mcw.KNOWN_SOCKETS[0]
session = args.session
manifest = (getattr(args, "manifest", None)
or str(NETVM_ROOT / "fleet" / "agents.json"))
dry_run = getattr(args, "dry_run", False)
res = rec.brief_agent(manifest, sock, session, dry_run=dry_run)
ok = res["action"] in ("briefed", "brief")
if as_json:
print(json.dumps({"ok": ok, "socket": sock,
"session": session,
"action": res["action"],
"detail": res["detail"]}, indent=2))
return
if ok:
print(c_green("\n✔ %s '%s': %s\n")
% ("Briefed" if res["action"] == "briefed"
else "Would brief", session, res["detail"]))
return
print(c_red("Error: cannot brief '%s': %s"
% (session, res["detail"])), file=sys.stderr)
sys.exit(1)
else:
if as_json:
print(json.dumps({"ok": False,
"error": "unknown_action",
"action": action}))
return
print(c_red("Error: unknown runtime action '%s'" % action),
file=sys.stderr)
sys.exit(1)
# ---------------------------------------------------------------------------
# Domain: TASKS (agent work queue: pending/claimed/done)
# ---------------------------------------------------------------------------
def _tasks_age(age_s):
if age_s is None:
return "-"
if age_s < 90:
return "%ds" % int(age_s)
if age_s < 5400:
return "%dm" % int(age_s // 60)
if age_s < 172800:
return "%dh" % int(age_s // 3600)
return "%dd" % int(age_s // 86400)
def cmd_work(args):
import box_work
action = getattr(args, "work_action", None)
if not action or action == "status":
box_work.cmd_status(args)
elif action == "start":
box_work.cmd_start(args)
elif action == "assign":
box_work.cmd_assign(args)
elif action == "merge":
box_work.cmd_merge(args)
elif action == "chats":
box_work.cmd_chats(args)
else:
box_work.cmd_status(args)
def cmd_tasks(args):
import runtime_reconcile as rec
action = getattr(args, "tasks_action", None) or "list"
as_json = getattr(args, "json", False)
tasks_dir = (getattr(args, "dir", None)
or str(NETVM_ROOT / "fleet" / "tasks"))
if action == "list":
queue = getattr(args, "queue", None) or "all"
rows = rec.list_tasks(tasks_dir, queue=queue)
if as_json:
print(json.dumps({"ok": True, "tasks": rows,
"dir": tasks_dir}, indent=2))
return
print(c_bold("\n=== TASK QUEUE ===\n"))
if not rows:
print(c_dim(" No tasks in %s." % queue))
print()
return
headers = ["QUEUE", "NAME", "OWNER", "AGE"]
table = [[r["queue"], r["name"][:44],
r["owner"] or badge_dim("-"),
_tasks_age(r["age_s"])] for r in rows]
print_table(headers, table)
print()
elif action == "show":
name = args.name
res = rec.read_task(tasks_dir, name)
if as_json:
print(json.dumps({"ok": "error" not in res,
"dir": tasks_dir, **res}, indent=2))
return
if "error" in res:
print(c_red("Error: %s" % res["error"]), file=sys.stderr)
sys.exit(1)
print(c_bold("\n=== TASK %s [%s] ===\n" % (
res["name"], res["queue"])))
print(res["text"].rstrip("\n"))
print()
elif action == "create":
res = rec.create_task(
tasks_dir, args.name, getattr(args, "title", ""),
getattr(args, "goal", ""), getattr(args, "steps", "") or "",
dry_run=getattr(args, "dry_run", False))
if as_json:
print(json.dumps({"ok": res["ok"], "dir": tasks_dir,
**{k: v for k, v in res.items()
if k != "ok"}}, indent=2))
return
if not res["ok"]:
print(c_red("Error: %s" % res["error"]), file=sys.stderr)
sys.exit(1)
print(c_green("\n✔ %s %s\n" % (
"Would create" if res.get("dry_run") else "Created",
res["path"])))
elif action == "claim":
res = rec.claim_task(tasks_dir, args.name, args.owner,
dry_run=getattr(args, "dry_run", False))
if as_json:
print(json.dumps({"ok": res["ok"], "dir": tasks_dir,
**{k: v for k, v in res.items()
if k != "ok"}}, indent=2))
return
if not res["ok"]:
print(c_red("Error: %s" % res["error"]), file=sys.stderr)
sys.exit(1)
print(c_green("\n✔ %s %s\n" % (
"Would claim" if res.get("dry_run") else "Claimed",
res["path"])))
elif action == "done":
res = rec.complete_task(tasks_dir, args.name,
getattr(args, "result", "") or "",
dry_run=getattr(args, "dry_run", False))
if as_json:
print(json.dumps({"ok": res["ok"], "dir": tasks_dir,
**{k: v for k, v in res.items()
if k != "ok"}}, indent=2))
return
if not res["ok"]:
print(c_red("Error: %s" % res["error"]), file=sys.stderr)
sys.exit(1)
print(c_green("\n✔ %s %s\n" % (
"Would complete" if res.get("dry_run") else "Completed",
res["path"])))
elif action == "requeue":
res = rec.requeue_task(tasks_dir, args.name,
dry_run=getattr(args, "dry_run", False))
if as_json:
print(json.dumps({"ok": res["ok"], "dir": tasks_dir,
**{k: v for k, v in res.items()
if k != "ok"}}, indent=2))
return
if not res["ok"]:
print(c_red("Error: %s" % res["error"]), file=sys.stderr)
sys.exit(1)
print(c_green("\n✔ %s %s\n" % (
"Would requeue" if res.get("dry_run") else "Requeued",
res["path"])))
elif action == "sweep":
manifest = (getattr(args, "manifest", None)
or str(NETVM_ROOT / "fleet" / "agents.json"))
dry_run = getattr(args, "dry_run", False)
res = rec.sweep_now(manifest, tasks_dir=tasks_dir,
dry_run=dry_run)
if as_json:
print(json.dumps({"ok": res["ok"], "dir": tasks_dir,
"dry_run": dry_run,
"live_sessions": res["live_sessions"],
"requeued": res["requeued"],
"errors": res["errors"]}, indent=2))
return
print(c_bold("\n=== TASK SWEEP%s ===\n" % (
" (dry-run)" if dry_run else "")))
if not res["requeued"] and not res["errors"]:
print(c_dim(" No stale claims."))
for c in res["requeued"]:
print(" %s task %s (%s)" % (
badge_ok("REQUEUED"), c_cyan(c["task"]), c["reason"]))
for e in res["errors"]:
print(" %s %s" % (badge_err("ERROR"), e))
print()
if not res["ok"]:
sys.exit(1)
else:
if as_json:
print(json.dumps({"ok": False,
"error": "unknown_action",
"action": action}))
return
print(c_red("Error: unknown tasks action '%s'" % action),
file=sys.stderr)
sys.exit(1)
# ---------------------------------------------------------------------------
# Domain: MUSE-CHOICES (Muse TUI A/B/C auto-answer daemon)
# ---------------------------------------------------------------------------
def cmd_muse_choices(args):
import muse_choice_watcher as mcw
action = getattr(args, "mc_action", None) or "status"
as_json = getattr(args, "json", False)
if getattr(args, "socket", None):
args.socket = mcw.resolve_socket(args.socket)
caller = os.environ.get("BOX_CALLER") or getattr(args, "from_agent", None) or "super"
if action == "on":
dry_run = getattr(args, "dry_run", False)
state = mcw.set_enabled(True, dry_run=dry_run, by=caller)
res = mcw.reconcile()
if as_json:
print(json.dumps({"ok": True, "desired": state, "reconcile": res}, indent=2))
return
mode = "DRY-RUN (logging only)" if dry_run else c_yellow("LIVE (typing A into Muse panes)")
print(c_green("\n✔ Muse choice auto-answers ON.") + f" [{mode}]\n")
for s in res["started"]:
print(f" {badge_ok('STARTED')} {c_cyan(s)}")
for s in res["already"]:
print(f" {badge_dim('RUNNING')} {s}")
for s in res.get("failed") or []:
print(f" {badge_err('FAILED')} {s}")
if not res["started"] and not res["already"] and not res.get("failed"):
print(c_dim(" No Muse panes found on known tmux sockets."))
print()
elif action == "off":
state = mcw.set_enabled(False, by=caller)
stopped = mcw.stop_all()
if as_json:
print(json.dumps({"ok": True, "desired": state, "stopped": stopped}, indent=2))
return
print(c_green("\n✔ Muse choice auto-answers OFF."))
for r in stopped:
if r.get("status") == "stopped-orphan":
label = "(orphan %s:%s)" % (r.get("socket"), r.get("pane"))
else:
label = r.get("pidfile")
print(f" {badge_dim('STOPPED')} {label} (pid {r.get('pid')})")
if not stopped:
print(c_dim(" No watchers were running."))
print()
elif action == "reconcile":
res = mcw.reconcile()
if as_json:
print(json.dumps({"ok": True, "reconcile": res}, indent=2))
return
print(f"\n Enabled: {c_bold(str(res['enabled']))} Dry-run: {res['dry_run']}")
for s in res["started"]:
print(f" {badge_ok('STARTED')} {c_cyan(s)}")
for s in res["stopped"]:
print(f" {badge_dim('STOPPED')} {s}")
for s in res["pruned"]:
print(f" {badge_dim('PRUNED')} {s}")
for s in res.get("failed") or []:
print(f" {badge_err('FAILED')} {s}")
if not res["started"] and not res["stopped"] and not res["pruned"] and not res.get("failed"):
print(c_dim(" Already in desired state."))
print()
elif action == "logs":
sock = getattr(args, "socket", None)
pane = getattr(args, "pane", None)
n = getattr(args, "n", 20)
path = mcw.logfile_for(sock, pane)
try:
with open(path) as f:
lines = f.readlines()
except OSError:
print(c_red(f"Error: no log at {path}"), file=sys.stderr)
sys.exit(1)
if as_json:
recs = []
for line in lines[-n:]:
try:
recs.append(json.loads(line))
except Exception:
recs.append({"raw": line.rstrip("\n")})
print(json.dumps({"ok": True, "log": path, "records": recs}, indent=2))
return
print(c_bold(f"\n=== {path} (last {n}) ===\n"))
for line in lines[-n:]:
print(line.rstrip("\n"))
print()
elif action == "resolve":
sock = getattr(args, "socket", None)
pane = getattr(args, "pane", None)
decision = getattr(args, "decision", None)
hf = mcw.read_hold(sock, pane)
if not hf:
if as_json:
print(json.dumps({"ok": True, "held": None,
"note": "nothing held"}, indent=2))
return
print(c_dim("\n Nothing held on %s:%s.\n" % (sock, pane)))
return
if decision == "deny" and hf.get("kind") not in mcw.NEGATIVE_KEYS:
msg = ("refusing deny on %s prompt (D2: questions always "
"resolve top-choice); use approve or wait for expiry"
% (hf.get("kind") or "?"))
if as_json:
print(json.dumps({"ok": False, "reason": msg}, indent=2))
return
print(c_red("\n Error: " + msg + "\n"), file=sys.stderr)
sys.exit(1)
hf["directive"] = decision
mcw.write_hold(sock, pane, hf)
mcw.audit("muse-choice-resolved",
name="%s:%s" % (os.path.basename(sock), pane),
caller=caller,
extra={"socket": sock, "pane": pane,
"decision": decision, "sig": hf.get("sig")})
if as_json:
print(json.dumps({"ok": True, "resolved": decision,
"pane": pane}, indent=2))
return
print(c_green("\n✔ Hold on %s:%s will %s within a poll."
% (sock, pane,
"approve" if decision == "approve" else "deny")))
print()
else: # status
desired = mcw.get_desired()
watchers = mcw.status_all()
answers = mcw.recent_answers(5)
held = mcw.list_holds()
if as_json:
print(json.dumps({"ok": True, "desired": desired,
"watchers": watchers, "held": held,
"recent_answers": answers}, indent=2))
return
state_badge = badge_ok("ON") if desired["enabled"] else badge_dim("OFF")
dry = " (dry-run)" if desired.get("dry_run") else ""
print("\n" + c_bold("=== MUSE CHOICE AUTO-ANSWERS ===") + f" {state_badge}{dry}")
upd = desired.get("updated_at") or "-"
by = desired.get("updated_by") or "-"
print(c_dim(f" Desired state: enabled={desired['enabled']} dry_run={desired.get('dry_run')} updated={upd} by={by}\n"))
if watchers:
headers = ["WATCHER", "STATUS", "PID", "LOG BYTES"]
rows = []
for w in watchers:
if w.get("orphan"):
badge = badge_warn("ORPHAN")
name = "(orphan %s:%s)" % (w.get("socket"), w.get("pane"))
else:
badge = badge_ok("ALIVE") if w["alive"] else badge_err("DEAD")
name = w["pidfile"]
rows.append([name, badge, str(w["pid"] or "-"),
str(w["log_bytes"] if w["log_bytes"] is not None else "-")])
print_table(headers, rows)
else:
print(c_dim(" No watcher state files."))
if held:
print(c_bold("\n Held prompts (resolve via: box muse-choices resolve --socket S --pane P approve|deny):"))
for h in held:
try:
left = max(0, int(float(h.get("held_until", 0)) - time.time()))
except (TypeError, ValueError):
left = -1
if mcw.hold_renews_forever(h, h.get("kind")):
when = "gate (renews, never auto-approves)"
elif left >= 0:
when = f"expires in {left}s"
else:
when = "expiry unknown"
print(f" • {badge_warn('HELD')} {c_bold(h.get('pane', '?'))} "
f"{h.get('kind')}/{h.get('key')} rule={h.get('rule')} "
f"{when}")
print(f" {c_dim((h.get('reason') or '')[:100])}")
print(f" {c_dim((h.get('text') or '')[:100])}")
if answers:
print(c_bold("\n Recent answers (box audit feed):"))
for a in answers:
opts = "; ".join(a.get("options") or [])[:80]
kind = a.get("kind") or "-"
key = a.get("key") or "-"
print(f" • {c_dim(a.get('ts', ''))} {c_bold(a.get('name', ''))} {kind}/{key} sig={a.get('sig')} ok={a.get('ok')}")
print(f" {c_dim(opts)}")
else:
print(c_dim("\n No answers recorded in box audit feed."))
print()
def resolve_sender(args) -> str:
explicit = getattr(args, "from_agent", None)
if explicit and explicit != DEFAULT_SENDER:
return explicit
caller_env = os.environ.get("BOX_CALLER")
if caller_env and caller_env in ("muse", "pip", "646", "opm", "super"):
return caller_env
return explicit or DEFAULT_SENDER
def sign_message(sender: str, message: str, key_path: Path = None, msg_id: str = None) -> tuple:
"""Signs message with SSH key (namespace 'dm') using ssh-keygen -Y sign.
Returns (signed_raw_wire_format, msg_id)."""
import tempfile
key_path = key_path or Path.home() / ".ssh" / "id_ed25519"
if not key_path.exists():
raise FileNotFoundError(f"Signing key not found: {key_path}")
mid = msg_id or hashlib.sha256(f"{sender}-{time.time()}-{os.urandom(8).hex()}".encode()).hexdigest()[:8]
payload = f"[from:{sender}] [id:{mid}]\n\n{message}"
with tempfile.TemporaryDirectory() as td:
payf = Path(td) / "payload"
with open(payf, "w") as f:
f.write(payload)
res = subprocess.run(
["ssh-keygen", "-Y", "sign", "-f", str(key_path), "-n", "dm", str(payf)],
capture_output=True, text=True, timeout=10
)
if res.returncode != 0:
raise RuntimeError(f"ssh-keygen sign failed: {res.stderr}")
sigf = Path(td) / "payload.sig"
with open(sigf, "r") as f:
sigblock = f.read().strip()
signed_wire = f"[from:{sender}] [id:{mid}]\n\n{message}\n\n{sigblock}"
return signed_wire, mid
# ---------------------------------------------------------------------------
# Domain: INVITE
# ---------------------------------------------------------------------------
def cmd_invite(args):
import invite
from invite_handler import salvage_blocked_node
action = getattr(args, "invite_action", None) or "status"
node = getattr(args, "node", None)
as_json = getattr(args, "json", False)
if action in ("status", "list"):
nodes = [node] if node else VALID_NODES
res = invite.fleet_invite_status(nodes)
if as_json:
print(json.dumps({"ok": True, "agents": res}, indent=2))
return
print("\n" + c_bold("=== FLEET INVITE STATUS ===") + "\n")
headers = ["NODE", "CODE", "REDEEMED", "USES LEFT", "USED", "REWARD"]
rows = []
for n in nodes:
it = res.get(n, {})
if not it.get("ok"):
rows.append([c_bold(n), c_red("ERROR"), "-", "-", "-",
(it.get("error") or "")[:40]])
continue
rows.append([c_bold(n), c_cyan(it.get("code") or "-"),
"yes" if it.get("has_redeemed") else c_green("no"),
str(it.get("uses_remaining")
if it.get("uses_remaining") is not None else "-"),
str(it.get("use_count")
if it.get("use_count") is not None else "-"),
((it.get("reward") or {}).get("title") or "-")[:40]])
print_table(headers, rows)
print()
elif action in ("code", "find"):
try:
res = invite.get_invite(node)
except invite.InviteError as e:
print(c_red(f" Error: {e}"), file=sys.stderr)
sys.exit(2)
if as_json:
print(json.dumps(res, indent=2))
elif res.get("ok"):
print(f" {c_bold(node)} invite code: {c_cyan(res['code'])}")
if res.get("uses_remaining") is not None:
print(f" Uses remaining: {res['uses_remaining']}")
print(f" Source: {res.get('source', 'api')}")
else:
print(c_red(f" Error: {res.get('error')}"), file=sys.stderr)
sys.exit(1)
elif action == "redeem":
code = getattr(args, "code", None)
method = getattr(args, "method", "auto")
notify_target = getattr(args, "notify", None) or getattr(args, "notify_target", None)
notify_agent = getattr(args, "notify_agent", None)
try:
if method != "api" or notify_target or notify_agent:
from invite_handler import InviteHandler
with InviteHandler(node) as h:
res_obj = h.redeem_code(code, method=method, notify_target=notify_target, notify_agent=notify_agent)
res = res_obj.to_dict()
res["ok"] = res_obj.success
else:
res = invite.redeem_invite(node, code)
except invite.InviteError as e:
print(c_red(f" Error: {e}"), file=sys.stderr)
sys.exit(2)
except Exception as e:
print(c_red(f" Error during redemption: {e}"), file=sys.stderr)
sys.exit(1)
if as_json:
print(json.dumps(res, indent=2))
elif res.get("ok"):
msg = f" ✔ Redeemed {res.get('code') or code} on {node}."
if res.get("detail"):
msg += f" {res['detail']}"
print(c_green(msg))
else:
reason_str = res.get("reason") or res.get("error") or "failed"
print(c_red(f" ✘ Redeem failed on {node}: {reason_str}"), file=sys.stderr)
if res.get("detail"):
print(c_dim(f" Detail: {res['detail']}"), file=sys.stderr)
if res.get("field_missing"):
print(c_yellow(f" Note: Expected redemption input field was missing or hidden on @{node}."), file=sys.stderr)
if res.get("loopback_notified"):
print(c_cyan(f" Loopback: Dispatched alert to {notify_agent or 'coordinator'}/{notify_target}."), file=sys.stderr)
sys.exit(1)
elif action == "salvage":
target = getattr(args, "node", "646") or "646"
notify_target = getattr(args, "notify", None) or getattr(args, "notify_target", None)
notify_agent = getattr(args, "notify_agent", None)
res = salvage_blocked_node(
target,
helper_node=getattr(args, "helper", None),
notify_target=notify_target,
notify_agent=notify_agent,
)
if as_json:
print(json.dumps(res, indent=2))
return
print(f"\n{c_bold('=== SALVAGE REPORT FOR ' + target.upper() + ' ===')}")
code = res.get("invite_code") or res.get("code_redeemed")
print(f" Invite Code to Credit: {c_cyan(str(code))}")
if res.get("success"):
print(c_green(f" Status: SUCCESS! Redeemed on {res.get('helper_node')}. 1 billion tokens credited to {target}!"))
else:
diag = res.get("error") or (res.get("redemption_result") or {}).get("detail") or "Redemption failed on helper peer"
print(c_yellow(f" Diagnosis: {diag}"))
action_hint = res.get("share_instruction") or f"Redeem code '{code}' via onboarding pipeline to grant 1B tokens to {target}."
print(f" Action: {action_hint}")
print(f" Command: {c_cyan('box onboard start <new_node> --email <client_email> --for ' + target)}")
if res.get("loopback_notified"):
print(c_cyan(f" Loopback: Notice dispatched to {notify_agent or 'coordinator'}/{notify_target}."))
print()
# ---------------------------------------------------------------------------
# Domain: USAGE
# ---------------------------------------------------------------------------
def cmd_usage(args):
import invite
node = getattr(args, "node", None) or getattr(args, "node_pos", None)
as_json = getattr(args, "json", False)
nodes = [node] if node else VALID_NODES
res = invite.fleet_usage(nodes)
if as_json:
print(json.dumps({"ok": True, "agents": res}, indent=2))
return
print("\n" + c_bold("=== FLEET USAGE LIMITS ===") + "\n")
headers = ["NODE", "WEEKLY RESET", "WEEKLY USED", "ADDITIONAL",
"ADD LEFT", "REDEEMED"]
rows = []
has_blocked = False
for n in nodes:
it = res.get(n, {})
if not it.get("ok"):
rows.append([c_bold(n), c_red("ERROR"), "-", "-",
(it.get("error") or "")[:30], "-"])
continue
if not it.get("stats_loaded", True):
rows.append([c_bold(n), c_yellow("UNLOADED"), "-", "-",
"Stats did not render", "-"])
continue
wu_val = it.get("weekly_used_pct")
wu = ("%d%%" % wu_val) if wu_val is not None else "-"
au_val = it.get("additional_used_pct")
au = ("%d%% used" % au_val) if au_val is not None else "-"
add_left = it.get("additional_left") or "-"
redeemed_val = it.get("has_redeemed")
redeemed_str = "yes" if redeemed_val else (c_green("no") if redeemed_val is False else "-")
if (wu_val is not None and wu_val >= 100 and au_val is not None and au_val >= 100) or ("0 tokens left" in add_left):
has_blocked = True
n_disp = c_red(f"● {n}")
else:
n_disp = c_bold(n)
rows.append([n_disp, it.get("weekly_reset") or "-",
wu, "%s / %s" % (it.get("additional_expires") or "-",
au),
add_left, redeemed_str])
print_table(headers, rows)
if has_blocked:
print("\n" + c_yellow(" ⚠ One or more agents have reached usage limits. Run 'box invite salvage <node>' to resolve.") + "\n")
else:
print()
# ---------------------------------------------------------------------------
# Domain: SETTINGS
# ---------------------------------------------------------------------------
def cmd_settings(args):
from settings_rpa import SettingsRPA
action = getattr(args, "settings_action", "usage") or "usage"
node = getattr(args, "node", "646") or "646"
as_json = getattr(args, "json", False)
with SettingsRPA(node) as rpa:
if action == "usage":
usage = rpa.read_usage()
if as_json:
print(json.dumps(usage.to_dict(), indent=2))
return
status_badge = badge_err("BLOCKED") if usage.is_blocked else badge_ok("ACTIVE")
redeemed_badge = c_green("No (Eligible to redeem)") if not usage.has_redeemed else "Yes (Already redeemed)"
print(f"\n{c_bold('=== Settings RPA Usage: ' + node + ' ===')}")
print(f" Plan: {usage.plan}")
print(f" Weekly Limit: {usage.weekly_reset_text} ({c_bold(str(usage.weekly_percent_used) + '%')} used)")
print(f" Extra Tokens: {usage.extra_tokens_remaining} ({c_bold(str(usage.extra_percent_used) + '%')} used)")
print(f" Has Redeemed: {redeemed_badge}")
print(f" Status: {status_badge}\n")
elif action == "check-redeem":
info = rpa.check_redeem_entrypoint()
print(json.dumps(info, indent=2))
# ---------------------------------------------------------------------------
# Domain: KPI (Spend Monitoring, Performance & Runtime Preservation)
# ---------------------------------------------------------------------------
def cmd_kpi(args):
import kpi
act = getattr(args, "kpi_action", "status") or "status"
as_json = getattr(args, "json", False)
if act == "status":
nodes = [args.node] if getattr(args, "node", None) else kpi.VALID_NODES
kpis = kpi.fleet_kpi(nodes)
if as_json:
print(json.dumps({k: v.to_dict() for k, v in kpis.items()}, indent=2))
return
print("\n" + c_bold("=== NETVM FLEET KPI & RUNTIME PRESERVATION DASHBOARD ===") + "\n")
header = f"{'NODE':<6} {'QUOTA':<10} {'CALLS':<12} {'JOBS':<10} {'SUBAGENTS':<11} {'TMUX':<6} {'UPTIME':<8} {'ROUTE':<9} {'EFFICIENCY':<15}"
sep = f"{'────':<6} {'─────────':<10} {'───────────':<12} {'─────────':<10} {'──────────':<11} {'────':<6} {'──────':<8} {'───────':<9} {'──────────────':<15}"
print(c_bold(header))
print(sep)
for n in nodes:
k = kpis.get(n)
if not k:
continue
q_str = f"{k.weekly_used_pct}%" if k.weekly_used_pct is not None else "Active"
c_str = f"{k.calls_sent} ({k.calls_verified}v)"
j_str = f"{k.jobs_completed}/{k.jobs_assigned}"
sub_str = str(k.subagents_active)
tmux_str = str(k.tmux_workers_active)
up_str = f"{k.uptime_hours}h"
print(f"{c_bold(k.node):<15} {q_str:<10} {c_str:<12} {j_str:<10} {sub_str:<11} {tmux_str:<6} {up_str:<8} {k.route_status:<9} {k.efficiency_rating:<15}")
print("\n" + c_dim("Run 'box kpi report <node>' for prescriptive runtime preservation advisories.\n"))
elif act == "report":
node = getattr(args, "node", "646") or "646"
res = kpi.get_agent_kpi(node)
if as_json:
print(json.dumps(res.to_dict(), indent=2))
return
print(f"\n{c_bold('=== KPI & RUNTIME REPORT: @' + res.node.upper() + ' ===')}")
print(f" Weekly Quota: {res.weekly_used_pct}% used")
print(f" Extra Tokens: {res.extra_tokens_remaining}")
print(f" Blocked Status: {'YES (LIMIT REACHED)' if res.is_blocked else 'NO (HEALTHY)'}")
print(f" Messages / Calls: {res.calls_sent} sent ({res.calls_verified} verified delivered)")
print(f" Jobs Dispatched: {res.jobs_completed} completed / {res.jobs_assigned} assigned")
print(f" Active Subagents: {res.subagents_active}")
print(f" Active Tmux Workers:{res.tmux_workers_active}")
print(f" Process Uptime: {res.uptime_hours} hours")
print(f" Route Health: {res.route_status}")
print(f" Efficiency Index: {res.efficiency_index} ({res.efficiency_rating})")
print(f"\n {c_yellow('[RUNTIME PRESERVATION ADVISORY]')}\n {res.preservation_advisory}\n")
elif act == "routes":
routes = {n: kpi.check_node_routes(n) for n in kpi.VALID_NODES}
if as_json:
print(json.dumps(routes, indent=2))
else:
print("\n" + c_bold("=== NETVM ROUTE HEALTH ==="))
for n, st in routes.items():
print(f" @{c_bold(n):<15} : {st}")
print()
elif act == "spawn-worker":
res = kpi.spawn_tmux_worker(args.node, args.session, args.worker_command)
if as_json:
print(json.dumps(res, indent=2))
else:
if res.get("ok"):
print(c_green(f"✔ {res.get('message')}"))
else:
print(c_red(f"✘ Failed to spawn worker: {res.get('error')}"), file=sys.stderr)
sys.exit(1)
elif act == "auto-spawn":
nodes = [args.node] if getattr(args, "node", None) else None
results = kpi.auto_spawn_workers(nodes=nodes, dry_run=getattr(args, "dry_run", False))
if as_json:
print(json.dumps(results, indent=2))
return
dry_label = c_yellow(" (DRY-RUN)") if getattr(args, "dry_run", False) else ""
print("\n" + c_bold(f"=== AUTO-SPAWN WORKER RECONCILIATION{dry_label} ==="))
for r in results:
n = r.get("node")
action = r.get("action")
if action == "spawned":
print(c_green(f" ✔ @{n:<5} : SPAWNED session '{r.get('session')}' ({r.get('work_type')}: {r.get('work_name')})"))
elif action == "would_spawn":
print(c_cyan(f" ? @{n:<5} : WOULD SPAWN session '{r.get('session')}' ({r.get('work_type')}: {r.get('work_name')})"))
elif action == "skip":
print(c_dim(f" - @{n:<5} : SKIP ({r.get('reason')})"))
elif action == "idle":
print(c_dim(f" - @{n:<5} : IDLE ({r.get('reason')})"))
elif action == "error":
print(c_red(f" ✘ @{n:<5} : ERROR ({r.get('error')})"))
print()
# ---------------------------------------------------------------------------
# Domain: ONBOARD (Agent-driven Onboarding & Invite Salvage Pipeline)
# ---------------------------------------------------------------------------
def cmd_onboard(args):
import onboard_pipeline
action = getattr(args, "onboard_action", "start") or "start"
as_json = getattr(args, "json", False)
if action == "start":
node = args.node
email = args.email
for_agent = getattr(args, "for_agent", None)
code = getattr(args, "code", None)
acct_name = getattr(args, "account_name", None)
res = onboard_pipeline.start_onboarding(node, email, beneficiary_node=for_agent, invite_code=code, account_name=acct_name)
if as_json:
print(json.dumps(res, indent=2))
return
if res.get("ok"):
print(f"\n{c_bold('=== ONBOARDING PIPELINE STARTED: ' + node.upper() + ' ===')}")
print(f" Target Node: {c_bold(node)}")
print(f" Client Email: {email}")
print(f" Beneficiary: @{res.get('beneficiary_node')} ({c_cyan(str(res.get('invite_code_queued')))})")
print(f" Status: {c_yellow(res.get('status', 'in_progress').upper())}")
print(f" Next Step: {res.get('message')}\n")
else:
print(c_red(f"\n✘ Onboarding failed: {res.get('error')}\n"), file=sys.stderr)
sys.exit(1)
elif action == "submit-otp":
node = args.node
otp = args.otp
email = getattr(args, "email", None)
res = onboard_pipeline.submit_onboarding_otp(node, otp, email=email)
if as_json:
print(json.dumps(res, indent=2))
return
if res.get("ok"):
print(f"\n{c_green('=== ONBOARDING & REDEMPTION COMPLETE ===')}")
print(f" Node: {c_bold(node)}")
print(f" Beneficiary: @{res.get('beneficiary_node')}")
print(f" Token Grant: +1,000,000,000 Muse tokens each")
print(f" Message: {c_green(res.get('message'))}\n")
else:
print(c_red(f"\n✘ OTP submission failed: {res.get('error')}\n"), file=sys.stderr)
sys.exit(1)
elif action == "status":
node = args.node
state = onboard_pipeline.OnboardState.load(node)
if not state:
print(c_red(f"No onboarding record found for node '{node}'"), file=sys.stderr)
sys.exit(1)
if as_json:
print(json.dumps(onboard_pipeline.asdict(state), indent=2))
return
print(f"\n{c_bold('=== ONBOARDING STATUS: @' + state.node.upper() + ' ===')}")
print(f" Email: {state.email}")
print(f" Current Stage: {c_cyan(state.stage)}")
print(f" Beneficiary Agent:@{state.beneficiary_node or '-'} (Code: {c_cyan(str(state.invite_code or '-'))})")
if state.detail:
print(f" Detail: {state.detail}")
if state.redemption_result:
rr = state.redemption_result
r_st = c_green("SUCCESS") if rr.get("ok") else c_red("FAILED")
print(f" Redemption: {r_st}")
print()
elif action == "connects":
conn_list = onboard_pipeline.get_all_connects()
if as_json:
print(json.dumps(conn_list, indent=2))
return
print(f"\n{c_bold('=== ACTIVE FLEET & CLIENT ONBOARD CONNECTS ===')}")
print(f" {'NODE':<8} {'TYPE':<16} {'STAGE / STATUS':<18} {'CDP':<8} {'INVITE':<10} {'ROLE / DETAIL'}")
print(" " + "─" * 78)
for c in conn_list:
node = c.get("node", "")
t_str = c.get("type", "")
st_str = c.get("stage", c.get("status", ""))
cdp = str(c.get("cdp_port") or "-")
code = c.get("invite_code") or "-"
role = c.get("role") or c.get("detail") or c.get("email") or ""
print(f" {node:<8} {t_str:<16} {st_str:<18} {cdp:<8} {code:<10} {role}")
print()
elif action == "salvage-wo":
node = getattr(args, "node", "646") or "646"
target_chat = getattr(args, "target", "646 tasks") or "646 tasks"
res = onboard_pipeline.issue_salvage_work_order(node, to_sidechat=target_chat)
if as_json:
print(json.dumps(res, indent=2))
return
if res.get("ok"):
print(c_green(f"\n✔ Cryptographically signed salvage work order dispatched for @{node} -> {target_chat}\n"))
else:
print(c_red(f"\n✘ Failed to dispatch work order: {res}\n"), file=sys.stderr)
sys.exit(1)
elif action == "feed-matrix":
matrix = onboard_pipeline.calculate_feeding_weights()
if as_json:
print(json.dumps({"ok": True, "feed_matrix": matrix}, indent=2))
return
print("\n" + c_bold("=== FLEET FEEDING & TOKEN ALLOCATION MATRIX ==="))
print(c_dim(" (Ranked by: Urgency + Work Done Over Time + Job Amount + Role Criticality)\n"))
headers = ["RANK", "AGENT", "ROLE", "FEED SCORE", "STATUS", "JOBS", "WORK DONE", "CODE"]
rows = []
for idx, r in enumerate(matrix, 1):
st = c_red("BLOCKED") if r["is_blocked"] else (c_yellow("LIMIT") if r["status"] == "LIMIT_REACHED" else c_green("ACTIVE"))
rows.append([
f"#{idx}",
c_bold(r["node"]),
r["role"],
c_cyan(str(r["feeding_weight"]) + " pts"),
st,
str(r["jobs_count"]),
f"{r['work_done_msgs']} msgs",
c_bold(r["code"]),
])
print_table(headers, rows)
print()
# ---------------------------------------------------------------------------
# Domain: CHROMEBOX (agent browser settings-menu toggles)
# ---------------------------------------------------------------------------
def cmd_chromebox(args):
from hatch_menu import toggles as menu_toggles
action = getattr(args, "chrome_action", None)
if action != "permissions":
print(c_red(" Error: expected 'permissions' (box chromebox "
"permissions <node> list|get|set|describe)"),
file=sys.stderr)
sys.exit(2)
node = getattr(args, "node", None)
as_json = getattr(args, "json", False)
perm_action = getattr(args, "perm_action", None) or "list"
if perm_action == "list":
tab = getattr(args, "tab", None)
try:
res = menu_toggles.list_toggles(node, tab=tab)
except menu_toggles.MenuError as e:
print(c_red(f" Error: {e}"), file=sys.stderr)
sys.exit(2)
if as_json:
print(json.dumps(res, indent=2))
return
if not res.get("ok"):
print(c_red(f" Error: {res.get('error')}"), file=sys.stderr)
sys.exit(1)
print("\n" + c_bold(f"=== CHROMEBOX TOGGLES: {node} ===") + "\n")
rows = []
for name in sorted(res.get("toggles", {})):
val = res["toggles"][name]
rows.append([name, c_red("-") if val is None else str(val)])
print_table(["TOGGLE", "VALUE"], rows)
print()
elif perm_action == "get":
name = getattr(args, "toggle", None)
try:
res = menu_toggles.get_toggle(node, name)
except menu_toggles.MenuError as e:
print(c_red(f" Error: {e}"), file=sys.stderr)
sys.exit(2)
if as_json:
print(json.dumps(res, indent=2))
elif res.get("ok"):
print(f" {c_bold(name)} = {c_cyan(res['value'])}")
else:
print(c_red(f" Error: {res.get('error')}"), file=sys.stderr)
sys.exit(1)
elif perm_action == "set":
name = getattr(args, "toggle", None)
value = getattr(args, "value", None)
try:
res = menu_toggles.set_toggle(node, name, value)
except menu_toggles.MenuError as e:
print(c_red(f" Error: {e}"), file=sys.stderr)
sys.exit(2)
if as_json:
print(json.dumps(res, indent=2))
elif res.get("ok"):
print(c_green(f" ✔ {name} = {res['value']} on {node} "
f"(readback verified)."))
else:
print(c_red(f" ✘ Set failed on {node}: {res.get('error')}"),
file=sys.stderr)
sys.exit(1)
elif perm_action == "describe":
tab = getattr(args, "tab", None)
try:
res = menu_toggles.describe_tab(node, tab)
except menu_toggles.MenuError as e:
print(c_red(f" Error: {e}"), file=sys.stderr)
sys.exit(2)
print(json.dumps(res, indent=2))
else:
print(c_red(f" Error: unknown action {perm_action!r}"),
file=sys.stderr)
sys.exit(2)
# ---------------------------------------------------------------------------
# Domain: DM (Direct Messaging & Work Orders)
# ---------------------------------------------------------------------------
def wait_for_reply(recipient: str, target: str, msg_id: str = None, timeout: int = 60) -> str:
"""Wait for recipient agent to reply, displaying an animated spinner."""
spinner_chars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
t0 = time.time()
idx = 0
dm_pos = DM_LOG.stat().st_size if DM_LOG.exists() else 0
found_reply = None
chat_hist_file = NETVM_ROOT / "logs" / "chat-history.jsonl"
hist_pos = chat_hist_file.stat().st_size if chat_hist_file.exists() else 0
sys.stdout.write("\n")
try:
while time.time() - t0 < timeout:
spin = spinner_chars[idx % len(spinner_chars)]
elapsed = int(time.time() - t0)
sys.stdout.write(f"\r {c_cyan(spin)} Awaiting response from {c_bold(recipient)}/{target}... ({elapsed}s/{timeout}s) [Ctrl+C to stop waiting]")
sys.stdout.flush()
idx += 1
# 1. Check DM_LOG for return message from recipient
if DM_LOG.exists() and DM_LOG.stat().st_size > dm_pos:
with open(DM_LOG, "r") as f:
f.seek(dm_pos)
for line in f:
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
ev_type = d.get("type", "")
sender = d.get("agent", "")
if sender == recipient and ev_type in ("sent", "send_done", "verified"):
m = d.get("msg") or d.get("body")
if m and (not msg_id or msg_id not in m):
found_reply = m
break
except Exception:
pass
dm_pos = f.tell()
if found_reply:
break
# 2. Check chat-history.jsonl (from harvester if active)
if chat_hist_file.exists() and chat_hist_file.stat().st_size > hist_pos:
with open(chat_hist_file, "r") as f:
f.seek(hist_pos)
for line in f:
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
if d.get("agent") == recipient:
m = d.get("text") or d.get("msg")
if m and (not msg_id or msg_id not in m) and not m.startswith("[from:super]"):
found_reply = m
break
except Exception:
pass
hist_pos = f.tell()
if found_reply:
break
# 3. Periodically poll thread messages via dm.py read every ~2.5s
if idx % 12 == 0:
try:
read_cmd = ["python3", str(BIN_DIR / "dm.py"), "read", "--agent", recipient, "--target", target, "--n", "3"]
r_read = subprocess.run(read_cmd, capture_output=True, text=True, timeout=8)
if r_read.returncode == 0 and r_read.stdout:
for block in r_read.stdout.split("\n---\n"):
block_s = block.strip()
if block_s and (not msg_id or f"[id:{msg_id}]" not in block_s) and not block_s.startswith("[from:super]"):
found_reply = block_s
break
except Exception:
pass
if found_reply:
break
time.sleep(0.2)
sys.stdout.write("\r" + " " * 85 + "\r")
sys.stdout.flush()
if found_reply:
print(f"\n{c_bold(c_cyan('[' + recipient + ']:'))}")
for l in found_reply.splitlines():
print(f" {l}")
print()
return found_reply
else:
print(c_yellow(f"\n (No response received from {recipient} within {timeout}s)\n"))
return None
except KeyboardInterrupt:
sys.stdout.write("\r" + " " * 85 + "\r")
sys.stdout.flush()
print(c_dim("\n (Stopped waiting for response)\n"))
return None
def get_available_targets(agent: str) -> list:
"""Find known sidechats and targets for an agent."""
targets = []
# 1. From job-sidechats.json
if (NETVM_ROOT / "job-sidechats.json").exists():
try:
with open(NETVM_ROOT / "job-sidechats.json") as f:
sc_data = json.load(f)
for k, v in sc_data.items():
if isinstance(v, dict):
if v.get("agent") == agent:
targets.append({"name": k, "type": "sidechat", "desc": f"registered coordination ({k})"})
elif agent in k:
targets.append({"name": k, "type": "sidechat", "desc": f"registered sidechat ({k})"})
except Exception:
pass
# 2. Add well-known agent sidechats
if agent == "646":
targets.append({"name": "646 tasks", "type": "sidechat", "desc": "primary task & check-in sidechat"})
targets.append({"name": "646-opm-work", "type": "sidechat", "desc": "opm work sidechat"})
elif agent == "opm":
targets.append({"name": "heartbeat", "type": "sidechat", "desc": "heartbeat & health sidechat"})
elif agent == "pip":
targets.append({"name": "646-pip-coord", "type": "sidechat", "desc": "pip & 646 coordination sidechat"})
# Deduplicate by name
seen = set()
unique_targets = []
for t in targets:
if t["name"] not in seen:
seen.add(t["name"])
unique_targets.append(t)
# Add Main Chat last with caution label
unique_targets.append({
"name": "main",
"type": "main",
"desc": "Main Chat (CAUTION: avoid per CHAT_POLICY.md)"
})
return unique_targets
def _render_chat_history(agent: str, target: str, limit: int = 5):
"""Fetch and display recent chat messages from thread."""
try:
read_cmd = ["python3", str(BIN_DIR / "dm.py"), "read", "--agent", agent, "--target", target, "--n", str(limit)]
r = subprocess.run(read_cmd, capture_output=True, text=True, timeout=12)
if r.returncode == 0 and r.stdout:
blocks = [b.strip() for b in r.stdout.split("\n---\n") if b.strip()]
if blocks:
print(c_dim("--- Recent Messages ---"))
for b in blocks[-limit:]:
if b.startswith("[from:super]"):
print(f"{c_green('[super]:')}")
elif f"[from:{agent}]" in b or f"from {agent}" in b:
print(f"{c_cyan('[' + agent + ']:')}")
else:
print(f"{c_dim('[message]:')}")
for line in b.splitlines()[:5]:
print(f" {line}")
print(c_dim("-----------------------\n"))
except Exception:
pass
def cmd_dm_chat(args):
agent = args.agent
target = getattr(args, "target", None)
timeout = getattr(args, "timeout", 60) or 60
print("\n" + c_bold(f"=== INTERACTIVE CONVERSATION SESSION: {c_cyan(agent.upper())} ===") + "\n")
# Target selection if not provided
if not target:
available = get_available_targets(agent)
print(c_bold("Select chat target:") + c_dim(" (Prefer sidechats to keep Main Chat clean)\n"))
for idx, t in enumerate(available, 1):
tag = c_green("[Sidechat - RECOMMENDED]") if t["type"] == "sidechat" else c_yellow("[Main Chat - USE WITH CAUTION]")
print(f" [{idx}] {c_bold(t['name']):<18} {tag} {c_dim(t['desc'])}")
print()
try:
choice = input(f"Choose target [1-{len(available)}] (default: 1): ").strip()
if not choice:
target = available[0]["name"]
else:
choice_idx = int(choice) - 1
if 0 <= choice_idx < len(available):
target = available[choice_idx]["name"]
else:
target = available[0]["name"]
except (ValueError, KeyboardInterrupt):
target = available[0]["name"]
print(f"\nEntering chat session with {c_bold(agent)} on {c_cyan(target)}...")
if target == "main":
print(c_yellow(" ⚠ WARNING: Main Chat targeted. Per CHAT_POLICY.md, keep interactions minimal."))
print(c_dim(" Commands: /exit (or /quit), /refresh (reload history), /switch (change target), /wo <title> <body>\n"))
# Initial history render
_render_chat_history(agent, target, limit=5)
# REPL loop
while True:
try:
prompt_str = f"{c_green('super')} ({c_cyan(target)}) > "
line = input(prompt_str).strip()
if not line:
continue
# Handle slash commands
if line in ("/exit", "/quit", ":q"):
print(c_dim("\nExited chat session.\n"))
break
elif line in ("/refresh", "/history"):
_render_chat_history(agent, target, limit=10)
continue
elif line == "/switch":
available = get_available_targets(agent)
print(c_bold("\nSelect new target:"))
for idx, t in enumerate(available, 1):
print(f" [{idx}] {t['name']} ({t['desc']})")
try:
c = input(f"Choose target [1-{len(available)}]: ").strip()
if c and int(c) - 1 in range(len(available)):
target = available[int(c) - 1]["name"]
print(f"Switched target to {c_cyan(target)}.\n")
_render_chat_history(agent, target, limit=5)
except Exception:
pass
continue
elif line.startswith("/wo "):
parts = line[4:].split(" ", 1)
wo_title = parts[0]
wo_body = parts[1] if len(parts) > 1 else wo_title
wo_id = hashlib.sha256(f"super-{agent}-{wo_title}-{time.time()}".encode()).hexdigest()[:8]
wo_content = f"[WO:{wo_id}] {wo_title} — {wo_body}"
signed_wire, mid = sign_message("super", wo_content, msg_id=wo_id)
print(c_dim(f"Issuing Work Order [WO:{wo_id}]..."))
r = subprocess.run([
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", "super", "--to", agent, "--target", target,
"--raw", signed_wire
], capture_output=True, text=True)
if r.returncode == 0:
print(c_green(f"✔ Work Order [WO:{wo_id}] delivered."))
wait_for_reply(agent, target, msg_id=wo_id, timeout=timeout)
else:
print(c_red(f"Delivery failed: {r.stderr or r.stdout}"))
continue
# Standard message
signed_wire, mid = sign_message("super", line)
r = subprocess.run([
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", "super", "--to", agent, "--target", target,
"--raw", signed_wire
], capture_output=True, text=True)
if r.returncode == 0:
print(c_green(f"✔ Delivered & verified [{mid}]."))
wait_for_reply(agent, target, msg_id=mid, timeout=timeout)
else:
print(c_red(f"Delivery failed: {r.stderr or r.stdout}"))
except (KeyboardInterrupt, EOFError):
print(c_dim("\nExited chat session.\n"))
break
def cmd_dm_send(args):
sender = resolve_sender(args)
recipient = args.to
target = getattr(args, "target", "main")
message = args.message
wait = getattr(args, "wait", False)
timeout = getattr(args, "timeout", 60) or 60
allow_main = getattr(args, "allow_main_chat", False)
if target == "main":
if not allow_main:
print(c_red("ERROR: Targeting Main Chat is blocked by CHAT_POLICY.md to prevent chat degradation."), file=sys.stderr)
print(c_dim(" To send routine task/payloads, use a sidechat: --target '<sidechat>'.\n To override intentionally, pass --allow-main-chat."), file=sys.stderr)
sys.exit(1)
print(c_yellow(" ⚠ [CHAT POLICY OVERRIDE] Main Chat targeted with --allow-main-chat. Keep interaction minimal."))
# Soft pre-flight grammar check against lookup_internal
try:
import lookup_engine
is_val, kind, hint = lookup_engine.validate_outbound_sentence(message)
if not is_val and hint:
print(c_yellow(f"\n ⚠ [GRAMMAR NOTICE]\n {hint}\n"), file=sys.stderr)
except Exception:
pass
should_sign = (sender == "super") and not getattr(args, "no_sign", False)
mid = None
if should_sign:
try:
signed_wire, mid = sign_message(sender, message)
cmd = [
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", sender,
"--to", recipient,
"--target", target,
"--raw",
]
if getattr(args, "expect_reply", False):
cmd.append("--expect-reply")
if getattr(args, "reply_timeout", None):
cmd.extend(["--reply-timeout", str(args.reply_timeout)])
cmd.append(signed_wire)
print(f"Dispatching Cryptographically Signed DM [{c_green('verified from:' + sender)}] -> [{c_bold(recipient)}/{target}]...")
res = subprocess.run(cmd)
if res.returncode != 0:
sys.exit(res.returncode)
if wait:
wait_for_reply(recipient, target, msg_id=mid, timeout=timeout)
sys.exit(0)
except Exception as e:
print(f"Signing notice: {e}, sending standard DM...", file=sys.stderr)
cmd = [
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", sender,
"--to", recipient,
"--target", target,
]
if getattr(args, "expect_reply", False):
cmd.append("--expect-reply")
if getattr(args, "reply_timeout", None):
cmd.extend(["--reply-timeout", str(args.reply_timeout)])
cmd.append(message)
print(f"Dispatching DM [{c_cyan('from:' + sender)}] -> [{c_bold(recipient)}/{target}]...")
res = subprocess.run(cmd)
if res.returncode != 0:
sys.exit(res.returncode)
if wait:
wait_for_reply(recipient, target, msg_id=mid, timeout=timeout)
sys.exit(0)
def cmd_dm_wo(args):
sender = resolve_sender(args)
recipient = args.to
target = getattr(args, "target", None)
if not target:
target = DEFAULT_AGENT_SIDECHATS.get(recipient, "main")
title = args.title
body = args.body
priority = getattr(args, "priority", "routine")
wait = getattr(args, "wait", True)
timeout = getattr(args, "timeout", 60) or 60
allow_main = getattr(args, "allow_main_chat", False)
if target == "main":
if not allow_main:
print(c_red("ERROR: Work Orders must target sidechats per CHAT_POLICY.md."), file=sys.stderr)
print(c_dim(" Defaulting to sidechat recommended. To override, pass --allow-main-chat."), file=sys.stderr)
sys.exit(1)
print(c_yellow(" ⚠ [CHAT POLICY OVERRIDE] Work Order targeted to Main Chat with --allow-main-chat."))
wo_id = hashlib.sha256(f"{sender}-{recipient}-{title}-{time.time()}".encode()).hexdigest()[:8]
prefix = "[URGENT] " if priority == "urgent" else ""
wo_content = f"{prefix}[WO:{wo_id}] [from {sender}] {title} — {body}"
should_sign = (sender == "super") and not getattr(args, "no_sign", False)
if should_sign:
try:
signed_wire, mid = sign_message(sender, wo_content, msg_id=wo_id)
cmd = [
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", sender,
"--to", recipient,
"--target", target,
"--raw",
signed_wire
]
print(f"Issuing Cryptographically Signed Work Order {c_green('[WO:' + wo_id + ']')} [{c_green('verified from:' + sender)}] -> [{c_bold(recipient)}/{c_cyan(target)}]...")
res = subprocess.run(cmd)
if res.returncode != 0:
sys.exit(res.returncode)
if wait:
wait_for_reply(recipient, target, msg_id=wo_id, timeout=timeout)
sys.exit(0)
except Exception as e:
print(f"Signing notice: {e}, sending standard work order...", file=sys.stderr)
cmd = [
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", sender,
"--to", recipient,
"--target", target,
"--expect-reply",
wo_content
]
print(f"Issuing Work Order {c_cyan('[WO:' + wo_id + ']')} [{c_cyan('from:' + sender)}] -> [{c_bold(recipient)}/{c_cyan(target)}]...")
res = subprocess.run(cmd)
if res.returncode != 0:
sys.exit(res.returncode)
if wait:
wait_for_reply(recipient, target, msg_id=wo_id, timeout=timeout)
sys.exit(0)
def cmd_dm_ack(args):
sender = resolve_sender(args)
recipient = args.to
target = getattr(args, "target", "main")
ref_id = args.id
ack_message = f"[ACK:{ref_id}]"
cmd = [
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", sender,
"--to", recipient,
"--target", target,
ack_message
]
print(f"Sending Acknowledgment {c_green('[ACK:' + ref_id + ']')} -> [{c_bold(recipient)}/{target}]...")
res = subprocess.run(cmd)
sys.exit(res.returncode)
def cmd_dm_verify(args):
cmd = ["python3", str(BIN_DIR / "dm.py"), "verify-sig"]
if getattr(args, "agent", None):
cmd.extend(["--agent", args.agent])
if getattr(args, "target", None):
cmd.extend(["--target", args.target])
if getattr(args, "message", None):
cmd.append(args.message)
res = subprocess.run(cmd)
sys.exit(res.returncode)
def cmd_dm_log(args):
n = getattr(args, "n", 25)
filter_agent = getattr(args, "agent", None)
filter_text = getattr(args, "filter", None)
if not DM_LOG.exists():
print(c_dim("dm-log.jsonl not found."))
return
def _match(data):
if filter_agent and (data.get("agent") != filter_agent and data.get("to") != filter_agent):
return False
if filter_text:
if filter_text.lower() not in json.dumps(data).lower():
return False
return True
with open(DM_LOG, "r") as f:
lines = f.readlines()
entries = []
if isinstance(n, int) and n >= 1:
# Walk newest-first, parsing only until n matches: identical
# result to a full parse + [-n:] at O(n) instead of O(file).
for line in reversed(lines):
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
except Exception:
continue
if not _match(data):
continue
entries.append(data)
if len(entries) >= n:
break
entries.reverse()
else:
# Legacy path: preserve entries[-n:] quirks for n <= 0.
for line in lines:
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
except Exception:
continue
if not _match(data):
continue
entries.append(data)
entries = entries[-n:]
if args.json:
print(json.dumps({"ok": True, "entries": entries}, indent=2))
return
print("\n" + c_bold(f"=== RECENT INTER-AGENT DMs (last {len(entries)}) ===") + "\n")
headers = ["TIME", "TYPE", "FROM -> TO", "TARGET", "STATUS / DETAIL"]
rows = []
for item in entries:
t_rel = parse_relative_time(item.get("ts", ""))
ev_type = item.get("type", "unknown")
# Colorize type badges
if ev_type == "sent" or ev_type == "send_done":
badge = c_green("SENT")
elif ev_type == "verified":
badge = c_green("✔ VERIFIED")
elif "fail" in ev_type:
badge = c_red("FAIL")
elif ev_type == "retry":
badge = c_yellow("RETRY")
elif ev_type == "send_start":
badge = c_blue("START")
else:
badge = c_dim(ev_type[:8].upper())
from_to = f"{item.get('agent', '-')} -> {item.get('to', '-')}"
target = item.get("target", "-")
msg = item.get("msg") or item.get("reason") or item.get("error") or ""
if not msg:
if ev_type == "retry":
msg = f"attempt {item.get('attempt', '?')} (id: {item.get('id', '-')})"
elif ev_type == "failed":
msg = f"delivery failed (id: {item.get('id', '-')}, verified: {item.get('verified', False)})"
elif ev_type == "sent":
msg = f"delivered (id: {item.get('id', '-')}, verified: {item.get('verified', True)})"
elif ev_type == "verified":
msg = f"confirmed in DOM (id: {item.get('id', '-')})"
elif ev_type == "send_done":
msg = f"completed send (id: {item.get('id', '-')})"
elif ev_type == "alias_resolved":
msg = f"resolved {item.get('target')} -> {item.get('thread_uuid', '')[:8]}"
elif ev_type == "nav_ok":
msg = f"navigated to thread {item.get('thread_uuid', '')[:8]}"
elif item.get("id"):
msg = f"id: {item.get('id')}"
msg_clean = " ".join(msg.split())
# Highlight protocol tokens
if "[WO:" in msg_clean:
msg_clean = re.sub(r"\[WO:([a-f0-9]+)\]", lambda m: c_magenta(m.group(0)), msg_clean)
if "[ACK:" in msg_clean:
msg_clean = re.sub(r"\[ACK:([a-f0-9]+)\]", lambda m: c_green(m.group(0)), msg_clean)
if "[JOB" in msg_clean:
msg_clean = re.sub(r"\[JOB ([^\]]+)\]", lambda m: c_cyan(m.group(0)), msg_clean)
if "[RESULT" in msg_clean:
msg_clean = re.sub(r"\[RESULT ([^\]]+)\]", lambda m: c_yellow(m.group(0)), msg_clean)
rows.append([
t_rel,
badge,
from_to,
target[:16],
msg_clean[:60] if msg_clean else c_dim("-")
])
print_table(headers, rows)
print("\n" + c_dim(" Commands: super dm tail | super dm send --to <agent> \"msg\" | super dm wo --to <agent> --title \"T\" \"body\"") + "\n")
def cmd_dm_tail(args):
filter_text = getattr(args, "filter", None)
print(c_bold("=== STREAMING DM LOG (Ctrl+C to stop) ===") + "\n")
if not DM_LOG.exists():
print(c_red("Error: dm-log.jsonl does not exist."))
return
with open(DM_LOG, "r") as f:
# Seek to end
f.seek(0, os.SEEK_END)
try:
while True:
line = f.readline()
if not line:
time.sleep(0.5)
continue
try:
data = json.loads(line.strip())
if filter_text and filter_text.lower() not in line.lower():
continue
ts = parse_relative_time(data.get("ts", ""))
ev_type = data.get("type", "")
sender = data.get("agent", "")
to = data.get("to", "")
msg = data.get("msg") or data.get("reason") or data.get("error") or ""
print(f"[{ts}] {c_cyan(ev_type.upper()):<12} {sender} -> {to}: {msg[:90]}")
except Exception:
pass
except KeyboardInterrupt:
print("\n" + c_dim("Tail stopped."))
TRANSFERS_REGISTRY_FILE = TRANSFERS_DIR / ".transfers-registry.json"
def _load_transfers_registry() -> dict:
if TRANSFERS_REGISTRY_FILE.exists():
try:
with open(TRANSFERS_REGISTRY_FILE, "r") as f:
return json.load(f)
except Exception:
return {}
return {}
def _save_transfers_registry(reg: dict):
TRANSFERS_DIR.mkdir(parents=True, exist_ok=True)
with open(TRANSFERS_REGISTRY_FILE, "w") as f:
json.dump(reg, f, indent=2)
def cmd_dm_send_file(args):
file_path = Path(args.file).resolve()
if not file_path.exists() or not file_path.is_file():
print(c_red(f"Error: File not found: {file_path}"), file=sys.stderr)
sys.exit(1)
recipient = args.to
target = getattr(args, "target", None)
if not target:
target = DEFAULT_AGENT_SIDECHATS.get(recipient, "main")
if target == "main":
print(c_yellow(" ⚠ [CHAT POLICY NOTE] Targeting Main Chat. Per CHAT_POLICY.md, avoid using Main Chat for routine payloads."))
note = getattr(args, "note", None)
wait = getattr(args, "wait", False)
timeout = getattr(args, "timeout", 60) or 60
# 1. Compute checksum and file stats
file_stat = file_path.stat()
size_bytes = file_stat.st_size
size_kb = size_bytes / 1024.0
hasher = hashlib.sha256()
with open(file_path, "rb") as f:
while chunk := f.read(65536):
hasher.update(chunk)
sha256_full = hasher.hexdigest()
sha256_short = sha256_full[:12]
# 2. Stage file in transfers directory
agent_transfers_dir = TRANSFERS_DIR / recipient
agent_transfers_dir.mkdir(parents=True, exist_ok=True)
ts_prefix = datetime.now().strftime("%Y%m%d_%H%M%S")
dest_filename = f"{ts_prefix}_{file_path.name}"
dest_path = agent_transfers_dir / dest_filename
shutil.copy2(file_path, dest_path)
# 3. Construct protocol payload pointer
file_id = hashlib.sha256(f"{recipient}-{dest_filename}-{time.time()}".encode()).hexdigest()[:8]
# Save to transfers registry
reg = _load_transfers_registry()
reg[file_id] = {
"file_id": file_id,
"recipient": recipient,
"original_name": file_path.name,
"original_path": str(file_path),
"staged_path": str(dest_path),
"sha256": sha256_full,
"size_bytes": size_bytes,
"size_kb": f"{size_kb:.1f} KB",
"staged_at": datetime.now(timezone.utc).isoformat(),
"note": note,
"sender": "super",
"target": target
}
_save_transfers_registry(reg)
lines = [
f"[FILE:{file_id}] {file_path.name} ({size_kb:.1f} KB, sha256:{sha256_short})",
f"Path: {dest_path}",
]
if note:
lines.append(f"Note: {note}")
payload_message = "\n".join(lines)
# 4. Dispatch cryptographically signed DM to recipient sidechat
signed_wire, mid = sign_message("super", payload_message, msg_id=file_id)
print(f"Staged file {c_bold(file_path.name)} -> {c_dim(str(dest_path))}")
print(f"Dispatching File Pointer {c_green('[FILE:' + file_id + ']')} [{c_green('verified from:super')}] -> [{c_bold(recipient)}/{c_cyan(target)}]...")
cmd = [
"python3", str(BIN_DIR / "dm.py"), "send",
"--agent", "super",
"--to", recipient,
"--target", target,
"--raw",
signed_wire
]
res = subprocess.run(cmd)
if res.returncode != 0:
print(c_red(f"File notification delivery failed with code {res.returncode}"), file=sys.stderr)
sys.exit(res.returncode)
print(c_green(f"✔ File notification delivered to {recipient}/{target}."))
if wait:
wait_for_reply(recipient, target, msg_id=file_id, timeout=timeout)
def cmd_dm_files(args):
subaction = getattr(args, "files_action", "list")
filter_agent = getattr(args, "agent", None)
if subaction == "clean":
older_than_days = getattr(args, "older_than", 7)
cutoff_sec = time.time() - (older_than_days * 86400)
reg = _load_transfers_registry()
removed_count = 0
retained_reg = {}
# Scan files on disk
for ad in (TRANSFERS_DIR.iterdir() if TRANSFERS_DIR.exists() else []):
if not ad.is_dir() or ad.name.startswith("."):
continue
if filter_agent and ad.name != filter_agent:
continue
for fp in list(ad.iterdir()):
if fp.is_file() and fp.stat().st_mtime < cutoff_sec:
try:
fp.unlink()
removed_count += 1
except Exception as e:
print(c_red(f"Error removing {fp}: {e}"))
for fid, rec in reg.items():
staged = Path(rec.get("staged_path", ""))
if staged.exists():
retained_reg[fid] = rec
_save_transfers_registry(retained_reg)
print(c_green(f"✔ Cleaned {removed_count} payload file(s) older than {older_than_days} day(s)."))
return
if not TRANSFERS_DIR.exists():
print(c_dim("No transferred files found (transfers/ directory is empty)."))
return
reg = _load_transfers_registry()
records = []
agent_dirs = [TRANSFERS_DIR / filter_agent] if filter_agent else sorted(TRANSFERS_DIR.iterdir())
for ad in agent_dirs:
if not ad.is_dir() or ad.name.startswith("."):
continue
agent_name = ad.name
for fp in sorted(ad.iterdir(), key=lambda p: p.stat().st_mtime, reverse=True):
if not fp.is_file() or fp.name.startswith("."):
continue
st = fp.stat()
size_kb = f"{st.st_size / 1024:.1f} KB"
mtime = datetime.fromtimestamp(st.st_mtime, tz=timezone.utc).isoformat()
t_rel = parse_relative_time(mtime)
clean_name = fp.name
m = re.match(r"^\d{8}_\d{6}_(.+)$", fp.name)
if m:
clean_name = m.group(1)
# Match in registry if available
reg_entry = next((r for r in reg.values() if r.get("staged_path") == str(fp)), {})
file_id = reg_entry.get("file_id", "-")
note = reg_entry.get("note", "")
records.append({
"agent": agent_name,
"file_id": file_id,
"filename": clean_name,
"staged_name": fp.name,
"path": str(fp),
"size_kb": size_kb,
"mtime": mtime,
"time_rel": t_rel,
"note": note
})
if args.json:
print(json.dumps({"ok": True, "files": records}, indent=2))
return
print("\n" + c_bold(f"=== TRANSFERRED PAYLOADS & STAGED FILES ({len(records)}) ===") + "\n")
headers = ["AGENT", "FILE ID", "FILENAME", "SIZE", "TRANSFERRED", "NOTE", "STAGED PATH"]
rows = []
for r in records:
rows.append([
c_cyan(r["agent"]),
c_green(r["file_id"]) if r["file_id"] != "-" else c_dim("-"),
c_bold(r["filename"]),
r["size_kb"],
r["time_rel"],
r["note"][:20] if r["note"] else c_dim("-"),
c_dim(r["path"])
])
print_table(headers, rows)
print("\n" + c_dim(" Commands: super dm send-file --to <agent> <path> | super dm files clean [--older-than N]") + "\n")
# ---------------------------------------------------------------------------
# Domain: THREAD (Chat Oversight via box-chat.py)
# ---------------------------------------------------------------------------
def cmd_thread_list(args):
agent = getattr(args, "agent", None)
if not agent:
print("\n" + c_bold("=== FLEET REGISTERED SIDECHATS & THREAD MAPPINGS ===") + "\n")
sc_file = NETVM_ROOT / "job-sidechats.json"
rows = []
headers = ["TARGET / ALIAS", "AGENT", "THREAD UUID", "PURPOSE / NOTES"]
if sc_file.exists():
try:
with open(sc_file, "r") as f:
data = json.load(f)
for k, v in sorted(data.items()):
if isinstance(v, dict):
ag = v.get("agent", "-")
uuid = v.get("thread_uuid") or v.get("uuid") or "-"
desc = v.get("description") or v.get("purpose") or "-"
rows.append([c_cyan(k), c_bold(ag), uuid, desc[:45]])
elif isinstance(v, str):
rows.append([c_cyan(k), "-", v, "-"])
except Exception as e:
print(c_red(f"Error reading job-sidechats.json: {e}"))
print_table(headers, rows)
print("\n" + c_dim(" To view specific thread: box thread view <agent> <uuid|alias>") + "\n")
print(c_dim(" To list agent active sessions: box thread list <agent>") + "\n")
return
threads = []
def is_noise(title):
t = (title or "").lower().strip()
return bool(re.search(r"generate.*(chat|session)?.*title", t))
# Fast path: try fast headless gateway via muse_hybrid (isolated per-node WARP egress)
try:
import muse_hybrid
gw_threads, gw_err = muse_hybrid.get_threads(agent)
if gw_threads and not gw_err:
for t in gw_threads:
if is_noise(t.get("title")):
continue
threads.append({
"id": t.get("session_id", ""),
"kind": "thread" if t.get("thread") else "chat",
"title": t.get("title") or "(no title)",
"participants": [agent],
"last_message_at": t.get("updated", "")
})
except Exception:
pass
# Fallback to box-chat.py / CDP if gateway returned no threads
if not threads:
cmd = ["python3", str(BIN_DIR / "box-chat.py"), "thread-list", agent]
res = subprocess.run(cmd, capture_output=True, text=True)
try:
data = json.loads(res.stdout)
raw_threads = data.get("threads", []) if data.get("ok") else []
threads = [t for t in raw_threads if not is_noise(t.get("title"))]
except Exception:
threads = []
if args.json:
print(json.dumps({"ok": True, "threads": threads}, indent=2))
return
print("\n" + c_bold(f"=== ACTIVE THREADS FOR {agent.upper()} ({len(threads)}) ===") + "\n")
headers = ["ID / UUID", "KIND", "TITLE", "PARTICIPANTS", "LAST ACTIVE"]
rows = []
for t in threads:
tid = t.get("id", "")
tid_disp = c_cyan(tid[:12]) if tid != "main" else c_bold("main")
kind = t.get("kind", "")
title = t.get("title", "")
parts = ", ".join(t.get("participants", []))
last_act = parse_relative_time(t.get("last_message_at", ""))
rows.append([tid_disp, kind, title[:35], parts, last_act])
print_table(headers, rows)
print("\n" + c_dim(f" View thread: super thread view {agent} <id>") + "\n")
def cmd_thread_view(args):
agent = args.agent
thread_id = args.thread_id
limit = getattr(args, "limit", 15)
messages = []
# 1. Resolve alias or name if known
try:
import dm
resolved = dm.resolve_sidechat_target(thread_id, agent)
if resolved and resolved != thread_id:
thread_id = resolved
except Exception:
pass
# 2. If short UUID prefix (6-12 hex chars), resolve against agent's thread list
if re.fullmatch(r"[0-9a-fA-F]{6,12}", str(thread_id).strip()):
try:
import muse_hybrid
gw_threads, _ = muse_hybrid.get_threads(agent)
if gw_threads:
for t in gw_threads:
sid = t.get("session_id", "")
if sid.lower().startswith(str(thread_id).strip().lower()):
thread_id = sid
break
except Exception:
pass
# Fast path: try fast headless gateway via muse_hybrid (isolated per-node WARP egress)
try:
import muse_hybrid
gw_msgs, gw_err = muse_hybrid.get_history(agent, thread_id=thread_id, limit=limit)
if gw_msgs and not gw_err:
for m in gw_msgs:
role = m.get("role", "unknown")
messages.append({
"from": {"name": role, "role": role},
"text": m.get("text", "")
})
except Exception:
pass
# Fallback to box-chat.py / CDP if gateway returned no messages
if not messages:
cmd = ["python3", str(BIN_DIR / "box-chat.py"), "thread-messages", agent, thread_id, "--limit", str(limit)]
try:
res = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
data = json.loads(res.stdout)
messages = data.get("messages", []) if data.get("ok") else []
except Exception:
messages = []
if not messages:
print(c_red(f"Error viewing thread {thread_id}: no messages returned"))
return
if args.json:
print(json.dumps({"ok": True, "messages": messages}, indent=2))
return
print("\n" + c_bold(f"=== THREAD {thread_id} ({agent}) — {len(messages)} messages ===") + "\n")
for msg in messages:
sender_info = msg.get("from", {})
sender_name = sender_info.get("name") or sender_info.get("role") or "unknown"
text = msg.get("text", "")
# Colorize sender
if sender_name in ("human", "super", "operator-main"):
sender_tag = c_yellow(f"[{sender_name}]")
else:
sender_tag = c_cyan(f"[{sender_name}]")
print(f"{sender_tag}:")
for line in text.split("\n"):
print(f" {line}")
print()
# ---------------------------------------------------------------------------
# Domain: JOB (Systemd Timers & Job Definitions)
# ---------------------------------------------------------------------------
def cmd_job_list(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "job-list"]
if getattr(args, "archived", False):
cmd.append("--archived")
res = subprocess.run(cmd, capture_output=True, text=True)
try:
data = json.loads(res.stdout)
except Exception:
print(c_red("Failed to load jobs:") + f"\n{res.stdout}")
return
if args.json:
print(json.dumps(data, indent=2))
return
jobs = data.get("jobs", [])
title_extra = " (INCLUDING ARCHIVED)" if getattr(args, "archived", False) else ""
print("\n" + c_bold(f"=== DEFINED JOBS ({len(jobs)}){title_extra} ===") + "\n")
headers = ["NAME", "AGENT", "SCHEDULE", "TIMEOUT", "STATUS", "DESCRIPTION"]
rows = []
for j in jobs:
sched = j.get("schedule", "-")
sched_disp = c_green(sched) if sched != "manual" else c_dim("manual")
is_arch = j.get("archived", False)
status_disp = c_yellow("ARCHIVED") if is_arch else c_green("ACTIVE")
rows.append([
c_bold(j.get("name", "")),
j.get("agent", "-"),
sched_disp,
f"{j.get('timeout', '-')}s",
status_disp,
(j.get("description") or "-")[:45]
])
print_table(headers, rows)
print("\n" + c_dim(" Commands: box job show <name> | box job archive <name> | box job unarchive <name> | box job run <name>") + "\n")
def cmd_job_archive(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "job-archive", args.name]
if getattr(args, "force", False):
cmd.append("--force")
res = subprocess.run(cmd, capture_output=True, text=True)
try:
data = json.loads(res.stdout)
except Exception:
print(c_red("Failed to archive job:") + f"\n{res.stderr or res.stdout}")
return
if args.json:
print(json.dumps(data, indent=2))
return
if data.get("ok"):
print(c_green(f"✔ Archived job '{args.name}' to jobs/archive/{args.name}.json"))
else:
print(c_red(f"Error archiving job '{args.name}': {data.get('error', 'unknown error')}"))
def cmd_job_unarchive(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "job-unarchive", args.name]
res = subprocess.run(cmd, capture_output=True, text=True)
try:
data = json.loads(res.stdout)
except Exception:
print(c_red("Failed to unarchive job:") + f"\n{res.stderr or res.stdout}")
return
if args.json:
print(json.dumps(data, indent=2))
return
if data.get("ok"):
print(c_green(f"✔ Unarchived job '{args.name}' to jobs/{args.name}.json"))
else:
print(c_red(f"Error unarchiving job '{args.name}': {data.get('error', 'unknown error')}"))
def cmd_job_show(args):
name = args.name
# 1. Fetch job definition via box-ctl
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "job-get", name]
res = subprocess.run(cmd, capture_output=True, text=True)
try:
jdata = json.loads(res.stdout)
except Exception:
print(c_red(f"Failed to query job '{name}': {res.stdout or res.stderr}"))
return
if not jdata.get("ok"):
print(c_red(f"Error: {jdata.get('error', 'Job not found')}"))
return
job = jdata.get("job", {})
# 2. Fetch timer status
tcmd = ["python3", str(BIN_DIR / "box-ctl.py"), "timer-status", name]
tres = subprocess.run(tcmd, capture_output=True, text=True)
tdata = None
try:
parsed_t = json.loads(tres.stdout)
if parsed_t.get("ok"):
tdata = parsed_t
except Exception:
pass
if args.json:
print(json.dumps({"ok": True, "job": job, "timer": tdata}, indent=2))
return
print("\n" + c_bold(f"=== JOB DEFINITION: {name} ===") + "\n")
print(f" Description : {job.get('description', '-')}")
print(f" Target Agent: {c_cyan(job.get('agent', '-'))}")
sched = job.get('schedule', '-')
print(f" Schedule : {c_green(sched) if sched != 'manual' else c_dim('manual')}")
print(f" Timeout : {job.get('timeout', 300)}s")
print(f" On Failure : {job.get('on_failure', 'alert')}")
if job.get("chain_next"):
print(f" Chain Next : {job.get('chain_next')}")
if job.get("dm_target"):
print(f" DM Target : {job.get('dm_target')}")
sidechat = job.get("sidechat")
if sidechat and any(sidechat.values()):
print(f"\n {c_bold('Sidechat Config:')}")
print(f" Create : {sidechat.get('create', False)}")
if sidechat.get("name_template"):
print(f" Name Template : {sidechat.get('name_template')}")
if sidechat.get("reuse_key"):
print(f" Reuse Key : {sidechat.get('reuse_key')}")
followup = job.get("followup")
if followup:
print(f"\n {c_bold('Follow-up Policy:')}")
print(f" Expect Reply : {followup.get('expect_reply', False)}")
print(f" Timeout : {followup.get('timeout', '-')}")
print(f" Nudges : {followup.get('nudges', 0)}")
if followup.get("escalate"):
print(f" Escalate To : {followup.get('escalate')}")
if followup.get("route"):
print(f" Route : {followup.get('route')}")
print(f"\n {c_bold('Prompt Template:')}")
prompt = job.get("prompt_template", "")
for line in prompt.splitlines():
print(f" {c_dim(line)}")
print(f"\n {c_bold('Systemd Timer Status:')}")
if tdata:
unit = tdata.get("unit", f"job-{name}.timer")
act = badge_ok() if tdata.get("active") else badge_err("INACTIVE")
en = str(tdata.get("enabled"))
cal = tdata.get("oncalendar") or "-"
last_run = tdata.get("last_run") or "-"
next_run = tdata.get("next_run") or "-"
res_str = tdata.get("last_result") or "-"
print(f" Unit File : {unit}")
print(f" Active : {act}")
print(f" Enabled : {en}")
print(f" Schedule : {c_cyan(cal)}")
print(f" Last Run : {last_run}")
print(f" Next Run : {next_run}")
print(f" Result : {res_str}")
else:
print(f" {badge_dim('NOT CONFIGURED')} (Run 'super job enable {name}' to activate)")
print()
def cmd_job_status(args):
name = getattr(args, "name", None)
if name:
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "timer-status", name]
else:
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "timer-list"]
res = subprocess.run(cmd, capture_output=True, text=True)
try:
data = json.loads(res.stdout)
except Exception:
print(c_red("Failed to query timers:") + f"\n{res.stdout}")
return
if args.json:
print(json.dumps(data, indent=2))
return
if name:
if not data.get("ok"):
print(c_red(f"Error querying timer '{name}': {data.get('error', 'Unknown error')}"))
return
print(f"\n{c_bold('Timer Status: ' + name)}")
print(f" Unit File : {data.get('unit')}")
print(f" Active : {badge_ok() if data.get('active') else badge_err('INACTIVE')}")
print(f" Enabled : {data.get('enabled')}")
print(f" Schedule : {c_cyan(data.get('oncalendar', '-'))}")
print(f" Last Run : {data.get('last_run') or '-'}")
print(f" Next Run : {data.get('next_run') or '-'}")
print(f" Result : {data.get('last_result') or '-'}\n")
else:
timers = data.get("timers", [])
print("\n" + c_bold(f"=== ACTIVE TIMERS ({len(timers)}) ===") + "\n")
headers = ["NAME", "UNIT", "ACTIVE", "ENABLED"]
rows = []
for t in timers:
act = badge_ok() if t.get("active") else badge_err("INACTIVE")
rows.append([c_bold(t.get("name", "")), t.get("unit", ""), act, str(t.get("enabled"))])
print_table(headers, rows)
print()
def cmd_job_create(args):
name = args.name
if not re.match(r"^[a-z0-9-]{1,64}$", name):
print(c_red("Error: Job name must match ^[a-z0-9-]{1,64}$"), file=sys.stderr)
sys.exit(1)
job_file = JOBS_DIR / f"{name}.json"
existed = job_file.exists()
update_mode = getattr(args, "update", False)
if existed and not update_mode:
print(c_red(f"Error: Job '{name}' already exists. Use --update to modify existing job."), file=sys.stderr)
sys.exit(1)
file_arg = getattr(args, "file", None)
if file_arg:
try:
if file_arg == "-":
raw_data = json.load(sys.stdin)
else:
with open(file_arg, "r") as f:
raw_data = json.load(f)
job_dict = raw_data
job_dict["name"] = name
except Exception as e:
print(c_red(f"Error loading JSON from '{file_arg}': {e}"), file=sys.stderr)
sys.exit(1)
else:
# Check required fields
if not args.agent:
print(c_red("Error: --agent is required when not using --file."), file=sys.stderr)
sys.exit(1)
if not args.prompt:
print(c_red("Error: --prompt is required when not using --file."), file=sys.stderr)
sys.exit(1)
job_dict = {
"name": name,
"agent": args.agent,
"schedule": args.schedule or "manual",
"description": args.description or f"Job {name}",
"prompt_template": args.prompt,
"timeout": args.timeout or 300,
"on_failure": getattr(args, "on_failure", "alert") or "alert",
"chain_next": getattr(args, "chain_next", None),
}
if getattr(args, "sidechat_create", False) or getattr(args, "sidechat_name", None) or getattr(args, "reuse_key", None):
job_dict["sidechat"] = {
"create": bool(getattr(args, "sidechat_create", False) or getattr(args, "sidechat_name", None) or getattr(args, "reuse_key", None)),
}
if getattr(args, "sidechat_name", None):
job_dict["sidechat"]["name_template"] = args.sidechat_name
if getattr(args, "reuse_key", None):
job_dict["sidechat"]["reuse_key"] = args.reuse_key
if getattr(args, "dm_target", None):
job_dict["dm_target"] = args.dm_target
# Call box-ctl.py job-put
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "job-put", name]
res = subprocess.run(cmd, input=json.dumps(job_dict), capture_output=True, text=True)
try:
resp = json.loads(res.stdout)
except Exception:
print(c_red(f"Failed to save job via box-ctl: {res.stdout or res.stderr}"), file=sys.stderr)
sys.exit(1)
if not resp.get("ok"):
print(c_red(f"Error saving job: {resp.get('error', 'unknown error')}"), file=sys.stderr)
if "detail" in resp:
print(c_dim(f"Detail: {json.dumps(resp['detail'])}"), file=sys.stderr)
sys.exit(1)
action_label = "Updated" if existed else "Created"
print(c_green(f"✔ {action_label} job '{name}' (saved to jobs/{name}.json and committed to git)"))
# Manage timer
schedule = job_dict.get("schedule", "manual")
no_enable = getattr(args, "no_enable", False)
timer_unit = Path.home() / ".config" / "systemd" / "user" / f"job-{name}.timer"
timer_existed = timer_unit.exists()
if schedule != "manual" and not no_enable:
if timer_existed:
subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-delete", name, "--keep-job"],
capture_output=True, text=True)
r_timer = subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-create", name],
capture_output=True, text=True)
try:
tresp = json.loads(r_timer.stdout)
if tresp.get("ok"):
print(c_green(f"✔ Systemd timer active: job-{name}.timer ({tresp.get('oncalendar')})"))
else:
print(c_yellow(f"⚠ Timer could not be activated: {tresp.get('error')}"))
except Exception:
print(c_yellow(f"⚠ Timer creation output: {r_timer.stdout or r_timer.stderr}"))
elif timer_existed and schedule == "manual":
subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-delete", name, "--keep-job"],
capture_output=True, text=True)
print(c_dim("Systemd timer removed because schedule is set to 'manual'."))
def cmd_job_enable(args):
name = args.name
job_file = JOBS_DIR / f"{name}.json"
if not job_file.exists():
print(c_red(f"Error: Job definition jobs/{name}.json not found."), file=sys.stderr)
sys.exit(1)
try:
jdata = json.loads(job_file.read_text())
if jdata.get("schedule") == "manual":
print(c_red(f"Error: Cannot enable timer for job '{name}' with schedule 'manual'."), file=sys.stderr)
print(c_dim("Update schedule to a valid cron pattern first using 'super job create --update'."), file=sys.stderr)
sys.exit(1)
except Exception as e:
print(c_red(f"Error reading job definition: {e}"), file=sys.stderr)
sys.exit(1)
timer_unit = Path.home() / ".config" / "systemd" / "user" / f"job-{name}.timer"
if not timer_unit.exists():
print(f"Timer unit not found for '{name}'. Creating systemd timer...")
res = subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-create", name],
capture_output=True, text=True)
else:
print(f"Activating existing timer for '{name}'...")
res = subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-enable", name],
capture_output=True, text=True)
try:
data = json.loads(res.stdout)
if data.get("ok"):
print(c_green(f"✔ Timer job-{name}.timer enabled and active."))
else:
print(c_red(f"Error enabling timer: {data.get('error', 'unknown error')}"))
sys.exit(1)
except Exception:
print(res.stdout or res.stderr)
def cmd_job_disable(args):
name = args.name
timer_unit = Path.home() / ".config" / "systemd" / "user" / f"job-{name}.timer"
if not timer_unit.exists():
print(c_yellow(f"Timer job-{name}.timer is not currently installed."))
return
print(f"Disabling timer for '{name}'...")
res = subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-disable", name],
capture_output=True, text=True)
subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-stop", name],
capture_output=True, text=True)
try:
data = json.loads(res.stdout)
if data.get("ok"):
print(c_green(f"✔ Timer job-{name}.timer disabled and stopped."))
else:
print(c_red(f"Error disabling timer: {data.get('error', 'unknown error')}"))
sys.exit(1)
except Exception:
print(res.stdout or res.stderr)
def cmd_job_delete(args):
name = args.name
job_file = JOBS_DIR / f"{name}.json"
timer_unit = Path.home() / ".config" / "systemd" / "user" / f"job-{name}.timer"
if not job_file.exists() and not timer_unit.exists():
print(c_red(f"Error: Job '{name}' not found."), file=sys.stderr)
sys.exit(1)
force = getattr(args, "force", False)
yes = getattr(args, "yes", False)
if not (yes or force):
prompt_msg = f"Are you sure you want to delete job '{c_bold(name)}' and its timer? [y/N]: "
try:
choice = input(prompt_msg).strip().lower()
if choice not in ("y", "yes"):
print(c_dim("Deletion aborted."))
return
except KeyboardInterrupt:
print("\n" + c_dim("Deletion aborted."))
return
# 1. Delete timer if exists
if timer_unit.exists():
print(f"Removing systemd timer job-{name}.timer...")
r_timer = subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "timer-delete", name, "--keep-job"],
capture_output=True, text=True)
try:
tdata = json.loads(r_timer.stdout)
if not tdata.get("ok") and not force:
print(c_red(f"Error deleting timer: {tdata.get('error')}"), file=sys.stderr)
sys.exit(1)
except Exception:
pass
# 2. Delete job file
if job_file.exists():
print(f"Removing job definition jobs/{name}.json...")
r_job = subprocess.run(["python3", str(BIN_DIR / "box-ctl.py"), "job-delete", name, "--force"],
capture_output=True, text=True)
try:
jdata = json.loads(r_job.stdout)
if jdata.get("ok"):
print(c_green(f"✔ Job '{name}' and its systemd units deleted successfully."))
else:
print(c_red(f"Error deleting job: {jdata.get('error')}"), file=sys.stderr)
sys.exit(1)
except Exception:
print(r_job.stdout or r_job.stderr)
def cmd_job_run(args):
name = args.name
follow = getattr(args, "follow", False)
job_file = JOBS_DIR / f"{name}.json"
if not job_file.exists():
print(c_red(f"Error: Job definition jobs/{name}.json not found."), file=sys.stderr)
sys.exit(1)
print(f"Triggering job dispatch for '{c_bold(name)}'...")
if not follow:
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "job-trigger", name]
res = subprocess.run(cmd)
sys.exit(res.returncode)
# Follow mode: open log files and track from current end position
dm_pos = DM_LOG.stat().st_size if DM_LOG.exists() else 0
job_pos = JOB_LOG.stat().st_size if JOB_LOG.exists() else 0
# Trigger job in background
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "job-trigger", name]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print(c_dim(f"Following execution logs for '{name}' (Press Ctrl+C to exit)..."))
start_time = time.time()
dispatched = False
completed = False
try:
while time.time() - start_time < 90: # 90s max follow
if proc.poll() is not None and not dispatched:
out_txt, err_txt = proc.communicate()
try:
pdata = json.loads(out_txt)
if not pdata.get("ok"):
print(c_red(f"Trigger failed: {pdata.get('error')}"))
return
else:
dispatched = True
except Exception:
pass
if JOB_LOG.exists() and JOB_LOG.stat().st_size > job_pos:
with open(JOB_LOG, "r") as f:
f.seek(job_pos)
for line in f:
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
if d.get("job_name") == name or name in str(d.get("job_id", "")):
ev = d.get("type") or d.get("event") or "event"
badge = c_green("DISPATCH") if "dispatched" in ev else (
c_red("FAILED") if "fail" in ev else c_cyan(ev.upper())
)
print(f" {badge} [{c_bold(name)}] {d.get('target', '')} {d.get('error', '')}")
if "failed" in ev or "timeout" in ev:
completed = True
except Exception:
pass
job_pos = f.tell()
if DM_LOG.exists() and DM_LOG.stat().st_size > dm_pos:
with open(DM_LOG, "r") as f:
f.seek(dm_pos)
for line in f:
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
msg = d.get("msg") or d.get("error") or ""
if name in msg or "[RESULT" in msg or "[WO" in msg:
ev_type = d.get("type", "")
sender = d.get("agent", "")
to = d.get("to", "")
badge = c_green("VERIFIED") if ev_type == "verified" else c_cyan(ev_type.upper())
print(f" {badge} DM {sender} -> {to}: {msg[:100]}")
if "[RESULT" in msg:
completed = True
except Exception:
pass
dm_pos = f.tell()
if completed:
print(c_green(f"✔ Job execution completed."))
break
time.sleep(0.5)
except KeyboardInterrupt:
print("\n" + c_dim("Stopped following."))
def cmd_job_log(args):
n = getattr(args, "n", 20)
filter_name = getattr(args, "name", None)
if not JOB_LOG.exists():
print(c_dim("job-log.jsonl not found."))
return
entries = []
with open(JOB_LOG, "r") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
if filter_name and d.get("job_name") != filter_name and filter_name not in d.get("job_id", ""):
continue
entries.append(d)
except Exception:
continue
entries = entries[-n:]
if args.json:
print(json.dumps({"ok": True, "entries": entries}, indent=2))
return
print("\n" + c_bold(f"=== RECENT JOB ACTIVITY (last {len(entries)}) ===") + "\n")
headers = ["TIME", "EVENT", "JOB ID", "AGENT", "DETAIL"]
rows = []
for item in entries:
t_rel = parse_relative_time(item.get("ts", ""))
ev = item.get("event", "-")
badge = c_green("DISPATCH") if "dispatched" in ev else c_dim(ev[:12])
job_id = item.get("job_id", "-")
agent = item.get("agent", "-")
detail = item.get("target") or item.get("error") or ""
rows.append([t_rel, badge, job_id[:25], agent, detail])
print_table(headers, rows)
print()
# ---------------------------------------------------------------------------
# Domain: WEB (Google Cloud VM Web Surfaces Probe)
# ---------------------------------------------------------------------------
def cmd_web_health(args):
endpoints = [
{"name": "Box Console (Front-Door)", "url": "https://box.muse-dev.online/"},
{"name": "Board Service", "url": "https://board.muse-dev.online/"},
{"name": "VM Reverse Proxy (sslip)", "url": "https://34-139-37-135.sslip.io/"},
{"name": "Box Timers API", "url": "https://box.muse-dev.online/api/box/timers"},
]
print("\n" + c_bold("=== GOOGLE CLOUD VM WEB SURFACES HEALTH (34.139.37.135) ===") + "\n")
results = []
headers = ["SURFACE", "ENDPOINT", "STATUS", "LATENCY", "SERVER / VIA"]
rows = []
for ep in endpoints:
t0 = time.time()
try:
req = urllib.request.Request(
ep["url"],
headers={"User-Agent": "super-cli/1.0 (bl; health-probe)"}
)
with urllib.request.urlopen(req, timeout=4) as resp:
elapsed_ms = int((time.time() - t0) * 1000)
code = resp.status
via = resp.headers.get("Via") or resp.headers.get("Server") or "ok"
badge = badge_ok(f"{code}")
except urllib.error.HTTPError as e:
elapsed_ms = int((time.time() - t0) * 1000)
code = e.code
via = e.headers.get("Via") or e.headers.get("Server") or "-"
# 401/403 means auth works as intended
if code in (401, 403):
badge = badge_ok(f"{code} AUTH_GATED")
else:
badge = badge_warn(f"{code}")
except Exception as e:
elapsed_ms = None
code = "ERR"
via = str(e)[:25]
badge = badge_err("UNREACHABLE")
lat_disp = f"{elapsed_ms}ms" if elapsed_ms is not None else "-"
rows.append([c_bold(ep["name"]), ep["url"], badge, lat_disp, via[:25]])
results.append({"name": ep["name"], "url": ep["url"], "code": code, "latency_ms": elapsed_ms})
print_table(headers, rows)
print("\n" + c_dim(" Operator note: box.muse-dev.online requires PIN or Bearer session cookie.") + "\n")
if args.json:
print(json.dumps({"ok": True, "results": results}, indent=2))
def cmd_web_test_auth(args):
print("\n" + c_bold("Testing Box API Authentication Gate:") + "\n")
url = "https://box.muse-dev.online/api/box/timers"
try:
req = urllib.request.Request(url, headers={"User-Agent": "super-cli/1.0"})
with urllib.request.urlopen(req, timeout=4) as resp:
print(c_yellow(f"Unexpected: Endpoint responded without auth: HTTP {resp.status}"))
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8", errors="ignore")
if e.code in (401, 403):
print(f" Endpoint: {url}")
print(f" Response: {badge_ok(f'HTTP {e.code}')} (Protection active)")
print(f" Body : {c_dim(body.strip()[:100])}\n")
else:
print(c_yellow(f"HTTP {e.code}: {body}"))
except Exception as e:
print(c_red(f"Error testing auth: {e}"))
def cmd_web_sync(args):
print("\n" + c_bold("=== DATA SYNC INTEGRITY (bl -> VM) ===") + "\n")
files = [
("DM Log", DM_LOG),
("Job Log", JOB_LOG),
("Control Audit", CTL_LOG),
]
headers = ["DATA STORE", "PATH", "SIZE", "RECORDS", "LAST MODIFIED"]
rows = []
for label, path in files:
if path.exists():
stat = path.stat()
size_kb = f"{stat.st_size / 1024:.1f} KB"
# Count lines
try:
with open(path, "r") as f:
lines = sum(1 for _ in f)
except Exception:
lines = 0
mtime = datetime.fromtimestamp(stat.st_mtime, tz=timezone.utc).isoformat()
mtime_rel = parse_relative_time(mtime)
rows.append([c_bold(label), str(path), size_kb, str(lines), mtime_rel])
else:
rows.append([c_bold(label), str(path), "-", "0", c_dim("missing")])
print_table(headers, rows)
print()
# ---------------------------------------------------------------------------
# Domain: CRED (Credentials & Onboarding Client)
# ---------------------------------------------------------------------------
def cmd_cred_initiate(args):
import cred_client
client = cred_client.CredClient()
res = client.initiate(args.node, args.email, service=getattr(args, "service", "muse"), account_name=getattr(args, "account_name", None))
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
else:
st = res.get("status")
if st == "awaiting_otp":
print("\n" + c_yellow(f"[APPROVAL_NEEDED] Code sent to {args.email} for node '{args.node}'.") + "\n")
print(f" Submit OTP with: super cred submit-otp --node {args.node} --otp <code>\n")
sys.exit(2)
elif st == "active":
print("\n" + c_green(f"[SUCCESS] Node '{args.node}' is already authenticated and active.") + "\n")
else:
print(f"[{st.upper()}] {res.get('message') or res.get('detail')}")
sys.exit(res.get("code", 1))
def cmd_cred_submit_otp(args):
import cred_client
client = cred_client.CredClient()
res = client.submit_otp(args.node, args.otp, email=getattr(args, "email", None))
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
else:
st = res.get("status")
if st == "active":
print("\n" + c_green(f"[SUCCESS] Node '{args.node}' successfully signed in!") + "\n")
else:
print(f"[{st.upper()}] {res.get('message') or res.get('detail')}")
sys.exit(res.get("code", 1))
def cmd_cred_status(args):
import cred_client
client = cred_client.CredClient()
res = client.status(args.node)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
else:
print("\n" + c_bold(f"=== CRED STATUS: {args.node} ===") + "\n")
print(f" Node : {c_bold(res['node'])}")
print(f" Email : {res['email']}")
print(f" Status : {res['status']}")
print(f" CDP Port : {res['cdp_port'] or '-'}")
alive_b = badge_ok("YES") if res['session_alive'] else badge_warn("NO")
print(f" Session Alive: {alive_b}")
if res["detail"]:
print(f" Detail : {c_dim(res['detail'])}")
print()
def cmd_cred_link_instagram(args):
import cred_client
client = cred_client.CredClient()
res = client.link_instagram(args.node, notify=getattr(args, "notify", False))
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
else:
print("\n" + c_bold(f"=== INSTAGRAM LINKING: {args.node} ===") + "\n")
if res.get("error"):
print(c_red(f" Error: {res['error']}"))
sys.exit(1)
print(f" Tailscale Portal: {c_cyan(res['portal_url'])}")
print(f" Direct IP Portal: {c_cyan(res['portal_ip_url'])}")
oauth_preview = res['direct_oauth_url'][:75] + "..." if res.get('direct_oauth_url') else "-"
print(f" OAuth URL : {c_dim(oauth_preview)}")
if getattr(args, "notify", False):
n_badge = badge_ok("SENT") if res['email_notified'] else badge_err("FAILED")
print(f" Email Alert : {n_badge}")
print("\n" + c_yellow(" → Tap either Tailscale link from your phone/browser to complete Meta age verification.") + "\n")
def cmd_cred_meta_audit(args):
import cred_client
client = cred_client.CredClient()
res = client.audit_meta(args.node)
if getattr(args, "json", False):
print(json.dumps(res, indent=2))
else:
print("\n" + c_bold(f"=== META ACCOUNTS CENTER AUDIT: {args.node} ===") + "\n")
if res.get("error"):
print(c_red(f" Error: {res['error']}"))
sys.exit(1)
email_str = res.get('email') or c_dim('(none / phone-only)')
print(f" Meta Account Email: {c_cyan(email_str)}")
profiles = res.get("profiles", [])
print(f" Linked Profiles ({len(profiles)}):")
for p_info in profiles:
p_type = p_info.get("type", "unknown")
p_name = p_info.get("name", "unknown")
badge = c_green(f"[{p_type}]") if p_type == "instagram" else c_magenta(f"[{p_type}]")
print(f" - {badge} {c_bold(p_name)}")
print()
def cmd_cred_list(args):
import cred_client
client = cred_client.CredClient()
items = client.list_all()
if getattr(args, "json", False):
print(json.dumps(items, indent=2))
else:
print("\n" + c_bold("=== FLEET CREDENTIAL & ONBOARDING STATUS ===") + "\n")
headers = ["NODE", "STATUS", "CDP", "ALIVE", "EMAIL"]
rows = []
for it in items:
alive_b = badge_ok("YES") if it["session_alive"] else badge_warn("NO")
rows.append([c_bold(it['node']), it['status'], str(it['cdp_port'] or '-'), alive_b, it['email']])
print_table(headers, rows)
print()
# ---------------------------------------------------------------------------
# Domain: HARVEST (Response & Readback Harvester)
# ---------------------------------------------------------------------------
def cmd_harvest_run(args):
cmd = [sys.executable, str(RESPONSE_HARVESTER_PY), "--once"]
if getattr(args, "agent", None):
cmd.extend(["--agent", args.agent])
if getattr(args, "dry_run", False):
cmd.append("--dry-run")
if getattr(args, "json", False):
cmd.append("--json")
try:
res = subprocess.run(cmd, capture_output=True, text=True)
if getattr(args, "json", False):
print(res.stdout.strip())
else:
if res.stdout.strip():
print(res.stdout.strip())
if res.stderr.strip():
print(c_yellow(res.stderr.strip()), file=sys.stderr)
except Exception as e:
print(c_red(f"Error running harvest: {e}"), file=sys.stderr)
sys.exit(1)
def cmd_harvest_status(args):
watermarks = {}
if WATERMARKS_FILE.exists():
try:
with open(WATERMARKS_FILE, "r") as f:
watermarks = json.load(f)
except Exception:
pass
sidechats = {}
if JOB_SIDECHATS_FILE.exists():
try:
with open(JOB_SIDECHATS_FILE, "r") as f:
sidechats = json.load(f)
except Exception:
pass
latest_seen = {}
if CHAT_HISTORY_LOG.exists():
try:
with open(CHAT_HISTORY_LOG, "r") as f:
for line in f:
if not line.strip(): continue
try:
rec = json.loads(line)
k = f"{rec.get('agent')}:{rec.get('thread_id')}"
latest_seen[k] = rec.get("ts")
except Exception:
continue
except Exception:
pass
if getattr(args, "json", False):
print(json.dumps({
"watermarks": watermarks,
"sidechats": sidechats,
"latest_events": latest_seen
}, indent=2))
return
now_str = datetime.now().strftime("%H:%M:%S")
print(f"\n=== RESPONSE HARVESTER STATUS === ({now_str} local)\n")
headers = ["AGENT", "THREAD / ALIAS", "ID", "WATERMARK", "LAST HARVESTED", "STATUS"]
rows = []
for agent in VALID_NODES:
wm_main = watermarks.get(f"{agent}:main", "-")
last_ts = latest_seen.get(f"{agent}:main")
status_b = badge_ok("ACTIVE") if wm_main != "-" else badge_dim("IDLE")
rows.append([
c_bold(agent),
"Main Chat",
c_dim("main"),
wm_main[:16] if wm_main != "-" else c_dim("-"),
parse_relative_time(last_ts) if last_ts else c_dim("none"),
status_b
])
for key, val in sidechats.items():
if key.startswith("_"): continue
if isinstance(val, dict):
tid = val.get("thread_uuid") or val.get("uuid")
a = val.get("agent", "opm")
elif isinstance(val, str):
tid = val
a = "opm"
else:
continue
if a == agent and tid:
wm_sc = watermarks.get(f"{agent}:{tid}", "-")
last_sc_ts = latest_seen.get(f"{agent}:{tid}")
status_sc = badge_ok("ACTIVE") if wm_sc != "-" else badge_dim("IDLE")
rows.append([
c_dim(f" └─ {agent}"),
key,
c_dim(tid[:8] + "…"),
wm_sc[:16] if wm_sc != "-" else c_dim("-"),
parse_relative_time(last_sc_ts) if last_sc_ts else c_dim("none"),
status_sc
])
print_table(headers, rows)
print(c_dim("\n Commands: super harvest run | super harvest tail\n"))
def _print_harvest_line(line: str, filter_text: str = None):
try:
e = json.loads(line)
text = e.get("text", "")
if filter_text and filter_text.lower() not in text.lower():
return
ts = e.get("ts", "")[11:19]
agent = e.get("agent", "unknown")
author = e.get("author", "unknown")
thread = e.get("thread_name") or e.get("thread_id", "main")
auth_color = c_green if author == "assistant" else c_cyan
snippet = text.replace("\n", " ")[:120]
print(f" {c_dim(ts)} {c_bold(f'[{agent}:{thread}]')} {auth_color(author)}: {snippet}")
except Exception:
pass
def cmd_harvest_tail(args):
if not CHAT_HISTORY_LOG.exists():
print(c_dim(f"Chat history log empty ({CHAT_HISTORY_LOG})"))
return
print(c_bold(f"=== TAILING CHAT HARVEST STREAM ({CHAT_HISTORY_LOG.name}) === (Ctrl+C to stop)") + "\n")
try:
with open(CHAT_HISTORY_LOG, "r") as f:
lines = f.readlines()
for line in lines[-15:]:
_print_harvest_line(line, getattr(args, "filter", None))
f.seek(0, os.SEEK_END)
while True:
line = f.readline()
if line:
_print_harvest_line(line, getattr(args, "filter", None))
else:
time.sleep(0.5)
except KeyboardInterrupt:
print()
# ---------------------------------------------------------------------------
# Domain: FOLLOWUP (Deadline Tracking & Nudges)
# ---------------------------------------------------------------------------
def cmd_followup_list(args):
followups = {}
if FOLLOWUPS_FILE.exists():
try:
with open(FOLLOWUPS_FILE, "r") as f:
followups = json.load(f)
except Exception:
pass
if getattr(args, "json", False):
print(json.dumps(followups, indent=2))
return
now_str = datetime.now().strftime("%H:%M:%S")
print(f"\n=== FOLLOW-UP TRACKING === ({now_str} local)\n")
headers = ["DM ID", "ROUTE", "TARGET", "NUDGES", "DEADLINE", "STATUS", "SNIPPET"]
rows = []
now = datetime.now(timezone.utc)
for dm_id, rec in sorted(followups.items(), key=lambda x: x[1].get("sent_at", ""), reverse=True):
st = rec.get("status", "pending")
if not getattr(args, "all", False) and st not in ("pending", "escalated"):
continue
route = f"{rec.get('sender', '?')} → {c_bold(rec.get('recipient', '?'))}"
target = rec.get("target", "main")
if len(target) > 18:
target = target[:17] + "…"
nudges = f"{rec.get('nudges_sent', 0)}/{rec.get('nudges_allowed', 2)}"
deadline_str = rec.get("deadline")
deadline_display = c_dim("-")
if deadline_str and st == "pending":
try:
dl_dt = datetime.fromisoformat(deadline_str.replace("Z", "+00:00"))
diff = int((dl_dt - now).total_seconds())
if diff > 0:
deadline_display = c_green(f"in {diff // 60}m")
else:
deadline_display = c_red(f"{abs(diff) // 60}m overdue")
except Exception:
deadline_display = deadline_str[:16]
if st == "pending":
status_badge = badge_warn("PENDING")
elif st == "escalated":
status_badge = badge_err("ESCALATED")
elif st == "resolved":
status_badge = badge_ok("RESOLVED")
else:
status_badge = badge_dim(st.upper())
snippet = rec.get("prompt_snippet") or rec.get("resolved_snippet") or ""
snippet = snippet.replace("\n", " ")[:35]
rows.append([
c_bold(dm_id[:8]),
route,
target,
nudges,
deadline_display,
status_badge,
c_dim(snippet)
])
print_table(headers, rows)
if not getattr(args, "all", False):
print(c_dim("\n (Showing pending & escalated only; use --all to view resolved records)"))
print(c_dim(" Commands: super followup sweep | super followup cancel <dm_id>\n"))
def cmd_followup_sweep(args):
cmd = [sys.executable, str(FOLLOWUP_SWEEPER_PY), "--once"]
if getattr(args, "dry_run", False):
cmd.append("--dry-run")
try:
res = subprocess.run(cmd, capture_output=True, text=True)
if res.stdout.strip():
print(res.stdout.strip())
if res.stderr.strip():
print(c_yellow(res.stderr.strip()), file=sys.stderr)
except Exception as e:
print(c_red(f"Error running sweeper: {e}"), file=sys.stderr)
sys.exit(1)
def cmd_followup_cancel(args):
if not FOLLOWUPS_FILE.exists():
print(c_red("No follow-ups found."), file=sys.stderr)
sys.exit(1)
try:
with open(FOLLOWUPS_FILE, "r") as f:
data = json.load(f)
except Exception as e:
print(c_red(f"Error reading follow-ups: {e}"), file=sys.stderr)
sys.exit(1)
target_id = args.dm_id.strip()
match_key = None
for k in data.keys():
if k == target_id or k.startswith(target_id):
match_key = k
break
if not match_key:
print(c_red(f"Follow-up ID '{target_id}' not found."), file=sys.stderr)
sys.exit(1)
data[match_key]["status"] = "canceled"
data[match_key]["canceled_at"] = datetime.now(timezone.utc).isoformat()
tmp_path = f"{FOLLOWUPS_FILE}.tmp.{os.getpid()}"
with open(tmp_path, "w") as f:
json.dump(data, f, indent=2)
os.replace(tmp_path, FOLLOWUPS_FILE)
print(c_green(f"● Cancelled follow-up {match_key}."))
# Also stand down the VM-side nudge controller (request-sweeper.py),
# which tracks dm_followup records independently of bl's local file.
# Best-effort: the local cancel already succeeded, so a VM failure
# (unreachable, no record, bad response) must not fail the command.
_vm_followup_cancel(match_key)
def _vm_followup_cancel(dm_id):
"""POST /api/box/followups/cancel so the VM-side sweeper stops nudging.
Best-effort: never raises. Prints a one-line outcome.
"""
import json as _json
import os as _os
import subprocess as _sp
import time as _time
import urllib.parse as _up
import urllib.request as _ur
import urllib.error as _ue
box_api = _os.environ.get("BOX_API_BASE", "https://box.muse-dev.online")
key = _os.environ.get("BOX_SIGN_KEY",
_os.path.expanduser("~/.ssh/id_ed25519"))
endpoint = "followups/cancel"
ts_now = str(int(_time.time()))
payload = ("%s\n%s" % (ts_now, endpoint)).encode()
try:
pr = _sp.run(["ssh-keygen", "-Y", "sign", "-f", key, "-n", "box"],
input=payload, capture_output=True, timeout=15)
sig = pr.stdout.decode().strip()
if not sig:
raise RuntimeError("empty signature")
except Exception as e:
print(c_yellow(" VM follow-up cancel skipped (signing failed: %s)" % e))
return
query = _up.urlencode({"identity": "bl", "ts": ts_now, "sig": sig})
url = "%s/api/box/followups/cancel?%s" % (box_api, query)
try:
req = _ur.Request(url,
data=_json.dumps({"dm_id": dm_id}).encode(),
headers={"Content-Type": "application/json",
"User-Agent": "super-cli/1.0 (bl)"},
method="POST")
with _ur.urlopen(req, timeout=30) as r:
resp = _json.load(r)
except _ue.HTTPError as e:
if e.code == 404:
print(c_dim(" VM: no dm_followup record (bl-only follow-up)."))
else:
try:
detail = e.read().decode("utf-8", errors="ignore")[:120]
except Exception:
detail = ""
print(c_yellow(" VM cancel failed: HTTP %s %s" % (e.code, detail)))
return
except Exception as e:
print(c_yellow(" VM cancel failed: %s" % e))
return
if resp.get("canceled"):
print(c_green(" VM: follow-up canceled (%s)."
% resp.get("request_id")))
else:
print(c_dim(" VM: %s." % resp.get("reason", "not canceled")))
# ---------------------------------------------------------------------------
# Domain: PIPELINE (Multi-Agent Workflow Pipelines)
# ---------------------------------------------------------------------------
def cmd_pipeline_run(args):
name = args.name.strip()
job_file = JOBS_DIR / f"{name}.json"
if not job_file.exists():
print(c_red(f"Error: Pipeline root job '{name}.json' not found in jobs/"), file=sys.stderr)
sys.exit(1)
import pipeline_engine
run_id = pipeline_engine.generate_pipeline_run_id(name)
entry = pipeline_engine.create_pipeline(name, run_id=run_id)
target = entry.get("target")
print(c_bold(f"\n=== LAUNCHING MULTI-AGENT PIPELINE [{name}] ==="))
print(f" Run ID: {c_cyan(run_id)}")
print(f" Target: {c_yellow(target)}")
print(f" Step 1: {c_bold(name)}\n")
cmd = [sys.executable, str(JOB_DISPATCH_PY), name, "--pipeline-run", run_id, "--step-n", "1"]
if getattr(args, "dry_run", False):
cmd.append("--dry-run")
res = subprocess.run(cmd)
if res.returncode == 0:
print(c_green(f"\n✔ Pipeline '{run_id}' dispatched step 1 successfully."))
print(c_dim(" Track with: super pipeline status | super pipeline history\n"))
else:
print(c_red(f"\n✖ Step 1 dispatch failed with code {res.returncode}"), file=sys.stderr)
sys.exit(res.returncode)
def cmd_pipeline_status(args):
import pipeline_engine
active = pipeline_engine.list_active_pipelines()
if getattr(args, "json", False):
print(json.dumps(active, indent=2))
return
now_str = datetime.now().strftime("%H:%M:%S")
print(f"\n=== ACTIVE MULTI-AGENT PIPELINES === ({now_str} local)\n")
if not active:
print(c_dim(" (no active pipeline runs currently executing)"))
print(c_dim(" Launch one with: super pipeline run <job_name>\n"))
return
headers = ["RUN ID", "PIPELINE", "TARGET", "STEP", "CURRENT AGENT", "ACTIVE JOB ID", "STARTED", "STATUS"]
rows = []
for p in active:
run_id = p.get("run_id", "-")
p_name = p.get("pipeline_name", "-")
target = p.get("target", "-")
cur_step_n = p.get("current_step", 1)
steps = p.get("steps", [])
last_step = steps[-1] if steps else {}
agent = last_step.get("agent", "-")
job_id = last_step.get("job_id", "-")
created_at = p.get("created_at")
rows.append([
c_bold(run_id),
p_name,
c_yellow(target),
f"Step {cur_step_n}",
c_cyan(agent),
c_dim(job_id[:16] + "…") if len(job_id) > 16 else job_id,
parse_relative_time(created_at) if created_at else c_dim("-"),
badge_ok("RUNNING"),
])
print_table(headers, rows)
# Details on steps for active runs
for p in active:
print(c_bold(f"\n Active Pipeline Details [{p.get('run_id')}]:"))
for s in p.get("steps", []):
st = s.get("status", "unknown")
st_badge = badge_ok("COMPLETED") if st == "completed" else badge_warn("RUNNING") if st == "dispatched" else badge_err(st.upper())
res_snippet = s.get("result", "")
res_disp = f" → {c_dim(res_snippet[:70])}" if res_snippet else ""
print(f" • Step {s.get('step_n')}: {c_bold(s.get('job_name'))} ({s.get('agent')}) [{st_badge}]{res_disp}")
print(c_dim("\n Commands: super pipeline run <name> | super pipeline history\n"))
def cmd_pipeline_history(args):
import pipeline_engine
limit = getattr(args, "limit", 20) or 20
history = pipeline_engine.list_pipeline_history(limit=limit)
if getattr(args, "json", False):
print(json.dumps(history, indent=2))
return
now_str = datetime.now().strftime("%H:%M:%S")
print(f"\n=== PIPELINE RUN HISTORY (Recent {len(history)}) === ({now_str} local)\n")
if not history:
print(c_dim(" (no pipeline history found)"))
return
headers = ["RUN ID", "PIPELINE", "TARGET", "STEPS", "STARTED", "COMPLETED", "STATUS"]
rows = []
for p in history:
run_id = p.get("run_id", "-")
p_name = p.get("pipeline_name", "-")
target = p.get("target", "-")
steps = p.get("steps", [])
step_summary = f"{len(steps)} step{'s' if len(steps) != 1 else ''}"
created_at = p.get("created_at")
completed_at = p.get("completed_at")
st = p.get("status", "unknown")
if st == "completed":
badge = badge_ok("COMPLETED")
elif st == "running":
badge = badge_warn("RUNNING")
else:
badge = badge_err("FAILED")
rows.append([
c_bold(run_id),
p_name,
c_yellow(target),
step_summary,
parse_relative_time(created_at) if created_at else c_dim("-"),
parse_relative_time(completed_at) if completed_at else c_dim("active"),
badge,
])
print_table(headers, rows)
print(c_dim("\n Commands: super pipeline status | super pipeline run <name>\n"))
def cmd_pipeline_stop(args):
import pipeline_engine
run_id = args.run_id.strip()
reason = getattr(args, "reason", "cancelled_by_operator") or "cancelled_by_operator"
entry = pipeline_engine.stop_pipeline(run_id, reason=reason)
if not entry:
print(c_red(f"Error: Pipeline run '{run_id}' not found."), file=sys.stderr)
sys.exit(1)
print(c_green(f"✔ Pipeline run '{entry.get('run_id')}' stopped/canceled."))
if getattr(args, "json", False):
print(json.dumps(entry, indent=2))
def cmd_pipeline_prune(args):
import pipeline_engine
max_age = getattr(args, "max_age", 1) or 1
pruned = pipeline_engine.prune_pipelines(max_age_hours=max_age)
if pruned:
print(c_green(f"✔ Pruned {len(pruned)} stale pipeline runs (> {max_age}h): {', '.join(pruned)}"))
else:
print(c_dim(f"✔ No stale running pipelines found (> {max_age}h)."))
if getattr(args, "json", False):
print(json.dumps({"pruned": pruned, "count": len(pruned)}, indent=2))
# ---------------------------------------------------------------------------
# Domain: DEPLOY (Multi-Agent Pipelines, Subagent Spawning, and Oversight)
# ---------------------------------------------------------------------------
def cmd_deploy(args):
action = getattr(args, "action", None)
if action == "subagent":
agent = args.agent
title = args.title or "subagent-task"
prompt = args.prompt
wait_val = getattr(args, "wait", 30)
wait = 30 if wait_val is None else int(wait_val)
print(c_bold(f"\n=== DEPLOYING SUBAGENT ON [{agent}] ==="))
print(f" Agent: {c_cyan(agent)}")
print(f" Title: {c_yellow(title)}")
print(f" Prompt: {c_dim(prompt[:90])}...\n")
import muse_hybrid
res, err = muse_hybrid.start_session(agent, title=title)
if err or not res:
print(c_red(f"✖ Failed to spawn subagent session: {err}"), file=sys.stderr)
sys.exit(1)
session_id = res.get("session_id")
print(c_green(f"✔ Subagent session spawned: {session_id}"))
try:
import subagent_tracker
subagent_tracker.register_session(agent, session_id, title=title, prompt=prompt)
except Exception:
pass
if prompt:
print(f" Dispatching task prompt to subagent (waiting up to {wait}s)...")
send_res, send_err = muse_hybrid.send_message(agent, prompt, thread_id=session_id, wait=wait)
if send_err:
print(c_yellow(f"Notice: {send_err}"))
else:
print(c_green("✔ Task prompt delivered."))
# Fetch fresh history to show assistant's initial work
msgs, _ = muse_hybrid.get_history(agent, thread_id=session_id, limit=5)
if msgs:
for m in msgs:
role = m.get("role")
if role == "assistant":
print(f"\n{c_bold('--- Subagent Response ---')}\n{m.get('text')}\n")
print(f" Oversee anytime with: {c_cyan(f'box thread view {agent} {session_id}')}\n")
return
# Pipeline deployment
pipe_name = getattr(args, "name", None)
if not pipe_name:
print(c_red("Error: Specify pipeline name (e.g. box deploy pipeline pipe-demo-step1)"), file=sys.stderr)
sys.exit(1)
args.name = pipe_name
cmd_pipeline_run(args)
# ---------------------------------------------------------------------------
# Domain: LOOP (Intrinsic Loop Strategy, Health, Break Taxonomy, and Control)
# ---------------------------------------------------------------------------
def cmd_loop_status(args):
agent = getattr(args, "agent", None)
status_filter = getattr(args, "status", None)
limit = getattr(args, "n", 30)
from gravity import reconstruct_loops
loops = reconstruct_loops(limit=limit, agent=agent, status_filter=status_filter)
if getattr(args, "json", False):
print(json.dumps({"ok": True, "loops": loops, "count": len(loops)}, indent=2))
return
prog = Path(sys.argv[0]).name if sys.argv and sys.argv[0] else "super"
if prog.endswith(".py"):
prog = "super"
print("\n" + c_bold(f"=== INTRINSIC LOOPS ({len(loops)} tracked) ===") + "\n")
headers = ["LOOP ID", "AGENT", "TARGET", "PURPOSE", "STATE", "AGE", "DEADLINE", "NUDGES", "DETAIL"]
rows = []
now = datetime.now(timezone.utc)
for l in loops:
lid = l.get("loop_id", "-")[:8]
ag = l.get("agent", "-")
tgt = l.get("target", "main")
if len(tgt) > 16:
tgt = tgt[:14] + ".."
purp = l.get("purpose", "-")
st = l.get("state", "LANDED")
if st == "FIRING":
st_badge = c_cyan("○ FIRING")
elif st == "LANDED":
st_badge = c_blue("● LANDED")
elif st == "SEEN":
st_badge = c_yellow("● SEEN")
elif st in ("ANSWERED", "CLOSED"):
st_badge = badge_ok(st)
elif st == "NUDGED":
st_badge = badge_warn("NUDGED")
elif st == "ESCALATED":
st_badge = badge_err("ESCALATED")
elif st == "BROKEN":
st_badge = badge_err("BROKEN")
else:
st_badge = badge_dim(st)
sent_rel = parse_relative_time(l.get("sent_at", ""))
dl_str = l.get("deadline", "")
if dl_str:
try:
dl_dt = datetime.fromisoformat(dl_str.replace("Z", "+00:00"))
diff_s = int((dl_dt - now).total_seconds())
if diff_s > 0:
dl_disp = c_green(f"in {diff_s // 60}m")
else:
dl_disp = c_red(f"{abs(diff_s) // 60}m ago")
except Exception:
dl_disp = dl_str[:10]
else:
dl_disp = c_dim("-")
nudges = f"{l.get('nudges_sent', 0)}/{l.get('nudges_allowed', 2)}"
detail = l.get("summary", "")[:30]
rows.append([c_bold(lid), ag, tgt, purp, st_badge, sent_rel, dl_disp, nudges, c_dim(detail)])
print_table(headers, rows)
print(c_dim(f"\n Commands: {prog} loop health | {prog} loop breaks | {prog} loop strat | {prog} loop vars | {prog} loop close <id>\n"))
def cmd_loop_health(args):
threshold = getattr(args, "threshold", None)
from gravity import get_fleet_loop_health
data = get_fleet_loop_health(threshold=threshold)
if getattr(args, "json", False):
print(json.dumps({"ok": True, **data}, indent=2))
return
summary = data.get("summary", {})
t_val = summary.get("threshold", 0.5)
print("\n" + c_bold(f"=== INTRINSIC FLEET LOOP HEALTH (Threshold: {t_val:.2f}) ===") + "\n")
headers = ["AGENT", "STATUS", "HEALTH RATIO", "LANDED", "ANSWERED", "VERDICT"]
rows = []
for ag, info in sorted(data.get("agents", {}).items()):
st = info.get("status", "IDLE")
if st == "HEALTHY":
badge = badge_ok("HEALTHY")
verd = c_green("PASS")
elif st == "DEGRADED":
badge = badge_err("DEGRADED")
verd = c_red("FAIL")
else:
badge = badge_dim("IDLE")
verd = c_dim("NO TRAFFIC")
hpct = info.get("health_pct", "-")
landed = str(info.get("landed", 0))
answered = str(info.get("answered", 0))
rows.append([c_bold(ag), badge, hpct, landed, answered, verd])
print_table(headers, rows)
ov = summary.get("overall_health_pct", "-")
tot_l = summary.get("total_landed", 0)
tot_a = summary.get("total_answered", 0)
fleet_st = c_green("HEALTHY") if summary.get("healthy") else c_red("DEGRADED")
print(f"\n {c_bold('Overall Fleet Health')}: {ov} ({tot_a}/{tot_l} loops closed/answered) — {fleet_st}\n")
def cmd_loop_breaks(args):
from gravity import diagnose_breaks
breaks = diagnose_breaks()
if getattr(args, "json", False):
print(json.dumps({"ok": True, "breaks": breaks, "count": len(breaks)}, indent=2))
return
if not breaks:
print("\n" + c_green("✔ All intrinsic loops and tracking mechanisms healthy. No breaks detected.") + "\n")
return
print("\n" + c_bold(f"=== INTRINSIC LOOP BREAK DIAGNOSTICS ({len(breaks)} issues) ===") + "\n")
headers = ["SEVERITY", "BREAK TYPE", "COMPONENT / AGENT", "DIAGNOSIS", "REMEDIATION"]
rows = []
for b in breaks:
sev = badge_err(b.get("severity", "CRITICAL")) if b.get("severity") == "CRITICAL" else badge_warn("WARNING")
btype = b.get("type", "-")
target = b.get("component") or b.get("agent") or "-"
diag = b.get("detail", "")
rem = b.get("remedy", "")
rows.append([sev, c_bold(btype), target, diag, c_dim(rem)])
print_table(headers, rows)
print()
def cmd_loop_strat(args):
subact = getattr(args, "strat_action", None) or "show"
from modulate import get_all_strategies, set_strategy_override, reset_strategy_override, modulate, render_tags, InputType
prog = Path(sys.argv[0]).name if sys.argv and sys.argv[0] else "super"
if prog.endswith(".py"):
prog = "super"
if subact == "show":
strats = get_all_strategies()
filter_type = getattr(args, "type", None)
if filter_type:
strats = [s for s in strats if s.get("input_type") == filter_type.lower()]
if getattr(args, "json", False):
print(json.dumps({"ok": True, "strategies": strats}, indent=2))
return
print("\n" + c_bold("=== INTRINSIC LOOP STRATEGY MATRIX (MODULATION) ===") + "\n")
headers = ["INPUT TYPE", "SUBTYPE", "AGENT", "TRACK", "PRIORITY", "TIMEOUT", "NUDGES", "ESCALATE", "SOURCE"]
rows = []
for s in strats:
itype = s.get("input_type", "")
sub = s.get("subtype") or "-"
ag = s.get("agent") or "-"
tr = str(s.get("track", "-"))
prio = s.get("priority", "normal")
if prio == "critical":
prio_disp = c_red("CRITICAL")
elif prio == "important":
prio_disp = c_yellow("IMPORTANT")
elif prio == "routine":
prio_disp = c_dim("ROUTINE")
else:
prio_disp = c_cyan(prio.upper())
timeout = f"{s.get('timeout_s', 0)}s"
nudges = str(s.get("nudges", 0))
esc = s.get("escalate") or "-"
src = c_yellow("OVERRIDE") if s.get("is_override") else c_dim("BUILTIN")
rows.append([c_bold(itype), sub, ag, tr, prio_disp, timeout, nudges, esc, src])
print_table(headers, rows)
print(c_dim(f"\n Modify: {prog} loop strat set <type> [--subtype S] [--agent A] [--priority P] [--timeout S] [--nudges N] [--escalate AGENT]\n"))
elif subact == "set":
itype = args.type
sub = getattr(args, "subtype", None)
agent = getattr(args, "agent", None)
res = set_strategy_override(
itype, sub, agent,
track=getattr(args, "track", None),
priority=getattr(args, "priority", None),
timeout_s=getattr(args, "timeout", None),
nudges=getattr(args, "nudges", None),
escalate=getattr(args, "escalate", None),
by="super"
)
target_desc = f"{itype}:{sub or '*'}:{agent or '*'}" if agent else f"{itype}:{sub or '*'}"
print(c_green(f"✔ Updated loop strategy override for '{target_desc}'."))
if getattr(args, "json", False):
print(json.dumps({"ok": True, "strategy": res}, indent=2))
elif subact == "reset":
itype = args.type
sub = getattr(args, "subtype", None)
agent = getattr(args, "agent", None)
ok = reset_strategy_override(itype, sub, agent, by="super")
target_desc = f"{itype}:{sub or '*'}:{agent or '*'}" if agent else f"{itype}:{sub or '*'}"
if ok:
print(c_green(f"✔ Reset loop strategy override for '{target_desc}' to default."))
else:
print(c_yellow(f"No override was active for '{target_desc}'."))
elif subact == "eval":
itype_str = args.type
sub = getattr(args, "subtype", None)
agent = getattr(args, "agent", None)
actionable = getattr(args, "actionable", False)
try:
itype = InputType(itype_str.lower())
except ValueError:
itype = InputType.MANUAL
pol = modulate(itype, sub.upper() if sub else None, agent=agent, actionable=actionable)
if getattr(args, "json", False):
print(json.dumps({"ok": True, "policy": pol.__dict__ if pol else None}, indent=2))
return
if pol:
print(f"\n{c_bold('Resolved Policy:')}")
print(f" Input Type : {pol.input_type.value}")
print(f" Subtype : {pol.subtype or '-'}")
print(f" Agent Scope: {agent or '-'}")
print(f" Priority : {pol.priority.value}")
print(f" Timeout : {pol.timeout_s}s")
print(f" Max Nudges : {pol.nudges}")
print(f" Escalate To: {pol.escalate or '-'}")
print(f" Rendered Tags: {c_cyan(render_tags(pol))}\n")
else:
print(f"\n{c_dim('Policy: Non-tracked input (no follow-up record created).')}\n")
def cmd_loop_vars(args):
subact = getattr(args, "vars_action", None) or "list"
from variables import Variables
v = Variables()
prog = Path(sys.argv[0]).name if sys.argv and sys.argv[0] else "super"
if prog.endswith(".py"):
prog = "super"
if subact == "list":
if getattr(args, "json", False):
print(json.dumps({"ok": True, "variables": v.all(), "schemas": {n: v.schema(n) for n in v.names()}}, indent=2))
return
names = v.names()
print("\n" + c_bold(f"=== RUNTIME CONTROL VARIABLES ({len(names)} registered) ===") + "\n")
headers = ["VARIABLE NAME", "VALUE", "DEFAULT", "UNIT", "RANGE", "DESCRIPTION"]
rows = []
for name in names:
val = v.get(name)
spec = v.schema(name)
d_val = spec.get("default")
unit = spec.get("unit", "-")
min_v = spec.get("min")
max_v = spec.get("max")
rng = f"{min_v}..{max_v}" if min_v is not None and max_v is not None else "-"
desc = spec.get("description", "")[:40]
val_str = str(val)
if val != d_val:
val_disp = c_cyan(f"{val_str} *")
else:
val_disp = val_str
rows.append([c_bold(name), val_disp, str(d_val), unit, rng, c_dim(desc)])
print_table(headers, rows)
print(c_dim(f"\n Adjust: {prog} loop vars set <name> <value> | Reset: {prog} loop vars reset <name> (* = modified)\n"))
elif subact == "get":
name = args.name
try:
val = v.get(name)
spec = v.schema(name)
if getattr(args, "json", False):
print(json.dumps({"ok": True, "name": name, "value": val, "schema": spec}, indent=2))
return
print(f"\n{c_bold('Variable: ' + name)}")
print(f" Current Value : {c_cyan(str(val))}")
print(f" Default Value : {spec.get('default')}")
print(f" Type : {spec.get('type')}")
print(f" Unit : {spec.get('unit', '-')}")
if "min" in spec and "max" in spec:
print(f" Allowed Range : {spec.get('min')} .. {spec.get('max')}")
print(f" Description : {spec.get('description')}\n")
except Exception as e:
print(c_red(f"Error: {e}"), file=sys.stderr)
sys.exit(1)
elif subact == "set":
name = args.name
val_raw = args.value
try:
spec = v.schema(name)
vtype = spec.get("type", "str")
if vtype == "int":
val = int(val_raw)
elif vtype == "float":
val = float(val_raw)
elif vtype == "bool":
val = val_raw.lower() in ("true", "1", "yes")
else:
val = val_raw
new_val = v.set(name, val, by="super")
print(c_green(f"✔ Variable '{name}' updated to {new_val}."))
if getattr(args, "json", False):
print(json.dumps({"ok": True, "name": name, "value": new_val}, indent=2))
except Exception as e:
print(c_red(f"Error setting variable: {e}"), file=sys.stderr)
sys.exit(1)
elif subact == "reset":
name = args.name
try:
def_val = v.reset(name, by="super")
print(c_green(f"✔ Variable '{name}' reset to default ({def_val})."))
if getattr(args, "json", False):
print(json.dumps({"ok": True, "name": name, "value": def_val}, indent=2))
except Exception as e:
print(c_red(f"Error resetting variable: {e}"), file=sys.stderr)
sys.exit(1)
elif subact == "history":
name = getattr(args, "name", None)
limit = getattr(args, "limit", 20)
entries = v.history(name=name, limit=limit)
if getattr(args, "json", False):
print(json.dumps({"ok": True, "history": entries, "count": len(entries)}, indent=2))
return
if not entries:
print("\n" + c_dim(" (no variable change history found)") + "\n")
return
print("\n" + c_bold(f"=== VARIABLE MODIFICATION AUDIT HISTORY ({len(entries)} entries) ===") + "\n")
headers = ["TIMESTAMP", "VARIABLE", "ACTION", "OLD VALUE", "NEW VALUE", "CHANGED BY"]
rows = []
for e in entries:
act = e.get("action", "")
if act == "set":
act_badge = c_cyan("SET")
elif act == "reset":
act_badge = c_yellow("RESET")
elif act == "rollback":
act_badge = c_magenta("ROLLBACK")
else:
act_badge = act
rows.append([
e.get("ts", "")[:19].replace("T", " "),
c_bold(e.get("name", "")),
act_badge,
str(e.get("old_value", "-")),
c_bold(str(e.get("new_value", "-"))),
e.get("by", "-")
])
print_table(headers, rows)
print(c_dim(f"\n Rollback: {prog} loop vars rollback <name> [--revision REV]\n"))
elif subact == "rollback":
name = args.name
rev = getattr(args, "revision", None)
try:
new_val = v.rollback(name, revision=rev, by="super")
print(c_green(f"✔ Variable '{name}' rolled back to {new_val}."))
if getattr(args, "json", False):
print(json.dumps({"ok": True, "name": name, "value": new_val}, indent=2))
except Exception as e:
print(c_red(f"Error rolling back variable: {e}"), file=sys.stderr)
sys.exit(1)
def cmd_loop_close(args):
dm_id = args.dm_id.strip()
cmd = [sys.executable, str(BIN_DIR / "box-ctl.py"), "loop-resolve", dm_id]
if getattr(args, "note", None):
cmd.append(args.note)
res = subprocess.run(cmd, capture_output=True, text=True)
try:
data = json.loads(res.stdout)
if data.get("ok"):
print(c_green(f"✔ Loop {dm_id} marked resolved/closed."))
else:
print(c_red(f"Error closing loop: {data.get('error')}"), file=sys.stderr)
except Exception:
print(res.stdout or res.stderr)
def cmd_loop_nudge(args):
dm_id = args.dm_id.strip()
if not FOLLOWUPS_FILE.exists():
print(c_red("followups.json not found."), file=sys.stderr)
return
try:
with open(FOLLOWUPS_FILE, "r") as f:
fdata = json.load(f)
rec = fdata.get(dm_id)
if not rec:
print(c_red(f"No pending follow-up found for ID '{dm_id}'."), file=sys.stderr)
return
rec["deadline"] = datetime.now(timezone.utc).isoformat()
with open(FOLLOWUPS_FILE, "w") as f:
json.dump(fdata, f, indent=2)
print(c_green(f"✔ Armed immediate nudge for loop {dm_id}. Running sweeper..."))
subprocess.run([sys.executable, str(FOLLOWUP_SWEEPER_PY), "--once"])
except Exception as e:
print(c_red(f"Error nudging loop: {e}"), file=sys.stderr)
def cmd_loop_sweep(args):
cmd_followup_sweep(args)
def cmd_loop_harvest(args):
cmd_harvest_run(args)
def cmd_loop_remediate(args):
dry_run = getattr(args, "dry_run", False)
from gravity import remediate_breaks
res = remediate_breaks(dry_run=dry_run)
if getattr(args, "json", False):
print(json.dumps({"ok": True, **res}, indent=2))
return
mode_str = c_yellow("DRY RUN (Simulated)") if dry_run else c_green("ACTIVE RECOVERY")
print("\n" + c_bold(f"=== PROGRESSIVE INTRINSIC LOOP REMEDIATION [{mode_str}] ===") + "\n")
remediated = res.get("remediated", [])
escalated = res.get("escalated", [])
if remediated:
print(c_bold(f"Auto-Remediated Soft Breakages ({len(remediated)}):"))
headers = ["ACTION", "LOOP ID", "AGENT", "REMEDIATION DETAIL"]
rows = []
for r in remediated:
act_badge = c_green("✔ " + r.get("action", ""))
rows.append([act_badge, c_bold(r.get("loop_id", "-")[:8]), r.get("agent", "-"), r.get("detail", "")])
print_table(headers, rows)
print()
else:
print(c_dim(" ✔ No soft breakages require remediation at this time.\n"))
if escalated:
print(c_red(c_bold(f"⚠ Escalated Hard Failures ({len(escalated)} - Manual Intervention Required):")))
headers = ["SEVERITY", "BREAK TYPE", "TARGET", "ISSUE DETAIL", "REMEDY"]
rows = []
for esc in escalated:
sev = badge_err("CRITICAL") if esc.get("severity") == "CRITICAL" else badge_warn("WARNING")
rows.append([sev, c_bold(esc.get("type", "-")), esc.get("agent") or esc.get("component") or "-", esc.get("detail", ""), c_dim(esc.get("remedy", ""))])
print_table(headers, rows)
print()
# ---------------------------------------------------------------------------
# CLI Argument Parser Setup
# ---------------------------------------------------------------------------
def cmd_ssh_mint(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "ssh-mint", args.name]
if args.force:
cmd.append("--force")
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print(c_green(f"✓ Minted ed25519 SSH keypair for '{args.name}'"))
print(f" Private key: {d.get('private_key')}")
print(f" Public key: {d.get('public_key')}")
print(f" Public key text: {d.get('public_key_content')}")
print(c_dim(" Registered into: ") + ", ".join(d.get("registered_in", [])))
else:
print(c_red(f"✗ Failed: {d.get('error')} ({d.get('code')})"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_ssh_list(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "ssh-list"]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
keys = d.get("keys", [])
print("\n" + c_bold(f"=== MANAGED SSH KEYS ({len(keys)}) ===") + "\n")
headers = ["NAME", "PRIVATE KEY", "PUB STATUS", "PUBLIC KEY PREVIEW"]
rows = []
for k in keys:
pub_txt = k.get("public_key") or ""
preview = (pub_txt[:32] + "..." + pub_txt[-16:]) if len(pub_txt) > 48 else pub_txt
rows.append([c_cyan(k.get("name")), k.get("private_key"), c_green("✓ present") if k.get("has_public") else c_red("missing"), preview])
print_table(headers, rows)
print("\n" + c_dim(" Mint new key: box ssh mint <name> [--force]") + "\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_ssh_show(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "ssh-show", args.name]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print(c_bold(f"=== SSH KEY DETAILS: {args.name} ==="))
print(f" Private key: {d.get('private_key')}")
print(f" Public key: {d.get('public_key')}")
print(f" Fingerprint: {d.get('fingerprint')}")
print(f"\n Public Key:\n {c_cyan(d.get('public_key_content'))}\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_ssh_ports(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "ssh-ports"]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
tunnels = d.get("tunnels", {})
jump = d.get("jump_host", "34.139.37.135")
print("\n" + c_bold(f"=== CONTAINER SSH & REVERSE TUNNEL REGISTRY (JUMP: {jump}) ===") + "\n")
headers = ["AGENT", "SSH PORT", "TERM PORT", "USER", "DIAL-IN COMMAND"]
rows = []
for name, info in tunnels.items():
port = info.get("port")
tport = info.get("terminal")
u = info.get("user", "hatch")
dial = f"ssh -J super@{jump} -p {port} {u}@localhost"
rows.append([c_cyan(name), str(port), str(tport), u, c_yellow(dial)])
print_table(headers, rows)
print("\n" + c_dim(" To execute remote cmd: ssh -J super@<jump> -p <port> hatch@localhost '<cmd>'") + "\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_ssh_info(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "ssh-info", args.name]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
name = d.get("account", args.name)
port = d.get("port")
u = d.get("container_user", "hatch")
jump = d.get("jump_host", "34.139.37.135")
print("\n" + c_bold(f"=== SSH DIAL-IN FOR AGENT: {name} ===") + "\n")
print(f" Container User: {c_cyan(u)}")
print(f" Reverse SSH Port:{c_yellow(str(port))}")
print(f" GCP Jump Host: {jump}")
print(f" From VM directly: {c_green(d.get('direct_from_vm', ''))}")
print(f" Via Jump Host: {c_green(d.get('jump_command', ''))}")
print(f"\n Modify .md via SSH:")
print(f" {c_dim(d.get('cat_example', ''))}\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_ssh_check(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "ssh-check"]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
except Exception:
sys.stdout.write(res.stdout)
return
if not d.get("ok"):
print(c_red(f"✗ Failed: {d.get('error')}"))
return
jump = d.get("jump_host", "?")
reachable = d.get("jump_reachable")
wall = d.get("latency_ms")
print("\n" + c_bold(f"=== CONTAINER SSH TUNNEL HEALTH (JUMP: {jump}) ===") + "\n")
if not reachable:
print(c_red(f" ✗ Jump host unreachable: {d.get('error', 'unknown')}"))
print(c_dim(" Tunnel states below are UNKNOWN (last sweep failed).") + "\n")
elif wall is not None:
print(c_dim(f" Sweep completed in {wall}ms at {d.get('checked_at', '')}") + "\n")
headers = ["AGENT", "SSH", "LAT", "BANNER", "TERM", "STATE", "DIAL"]
rows = []
accounts = d.get("accounts", {})
def _state(v):
if v is True:
return c_green("UP")
if v is False:
return c_red("DOWN")
return c_dim("?")
for name, info in accounts.items():
sport = info.get("ssh_port", "?")
tport = info.get("term_port", "?")
lat = info.get("ssh_latency_ms")
lat_s = f"{lat}ms" if lat is not None else "-"
banner = (info.get("ssh_banner") or "-")[:28]
therm = info.get("term_http") or ""
tstate = _state(info.get("term_up"))
if info.get("term_up") and therm:
tstate += c_dim(f" {therm[:18]}")
u = info.get("container_user", "hatch")
dial = f"ssh -J super@{jump} -p {sport} {u}@localhost"
rows.append([c_cyan(name), f":{sport} {_state(info.get('ssh_up'))}",
lat_s, banner, f":{tport}", tstate, c_yellow(dial)])
print_table(headers, rows)
print()
def cmd_md_audit(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md-audit"] + (args.accounts or [])
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
agents = d.get("agents", {})
print("\n" + c_bold(f"=== MUSE AGENT .MD & OPERATIONAL DRIVE AUDIT ({len(agents)} AGENTS) ===") + "\n")
for acct, info in agents.items():
if not info.get("connected"):
print(c_red(f"[{acct.upper()}] ✗ Connection failed: {info.get('error')}"))
continue
score = info.get("drive_score", 0)
score_str = c_green(f"{score}/100 [HIGH DRIVE]") if score >= 75 else (c_yellow(f"{score}/100 [PARTIAL]") if score >= 50 else c_red(f"{score}/100 [LOW/STALE]"))
vm = info.get("vm_id", "unknown")
print(f"[{c_bold(acct.upper())}] Drive: {score_str} VM: {c_dim(vm)}")
headers = ["FILE", "STATUS", "SIZE", "MODIFIED"]
rows = []
for fname, finfo in info.get("files", {}).items():
exists = finfo.get("exists")
st = c_green("✓ present") if exists else c_red("✗ missing")
sz = f"{finfo.get('size', 0)} B"
mod = (finfo.get("modified") or "-")[:19]
rows.append([fname, st, sz, mod])
print_table(headers, rows)
issues = info.get("issues", [])
if issues:
print(c_dim(" Issues / Gaps:"))
for iss in issues:
print(c_yellow(f" • {iss}"))
print()
print(c_dim(" Fix agent drive: box md inject-drive <agent> | box md sync-all") + "\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_list(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md-list", args.account, args.path]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
entries = d.get("entries", [])
print("\n" + c_bold(f"=== FILES IN {args.account}:{args.path or '/'} ({len(entries)}) ===") + "\n")
headers = ["NAME", "TYPE", "SIZE", "MODIFIED"]
rows = []
for e in entries:
t = e.get("type", "file")
name_colored = c_cyan(e.get("name")) if t == "directory" else e.get("name")
rows.append([name_colored, t, str(e.get("size", "-")), (e.get("modifiedAt") or "-")[:19]])
print_table(headers, rows)
print()
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_read(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md-read", args.account, args.filename]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
text = d.get("text", "")
print(f"\n{c_bold('--- ' + args.account + ':' + args.filename + ' (' + str(len(text)) + ' chars) ---')}\n")
print(text)
print()
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_write(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md-write", args.account, args.filename]
if args.file:
cmd.extend(["--file", args.file])
elif args.content:
cmd.extend(["--content", args.content])
else:
print(c_red("Error: specify --content or --file"))
return
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print(c_green(f"✓ Wrote {d.get('bytes_written')} bytes to {args.account}:{args.filename} via Hatch"))
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_diff(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md-diff", args.account, args.filename]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
if d.get("identical"):
print(c_green(f"✓ {args.account}:{args.filename} matches local shared/operators/{args.filename} exactly."))
else:
print(f"\n{c_bold('=== DIFF: ' + args.account + ':' + args.filename + ' vs shared/operators/' + args.filename + ' ===')}\n")
diff = d.get("diff", "")
for line in diff.splitlines():
if line.startswith("+"):
print(c_green(line))
elif line.startswith("-"):
print(c_red(line))
elif line.startswith("@@"):
print(c_cyan(line))
else:
print(line)
print()
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_inject_drive(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md-inject-drive", args.account]
if args.force:
cmd.append("--force")
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print("\n" + c_bold(f"=== INJECTED OPERATIONAL DRIVE INTO AGENT: {args.account.upper()} ===") + "\n")
for u in d.get("updates", []):
print(c_green(f" ✓ Injected {u.get('file'):26} ({u.get('bytes')} bytes)"))
print(f"\n{c_green('✓ Successfully activated SOUL.md, PROACTIVE_PREFERENCES.md, and HEARTBEAT.md!')}\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_sync_all(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md-sync-all"]
if args.force:
cmd.append("--force")
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print("\n" + c_bold("=== FLEET-WIDE OPERATIONAL DRIVE INJECTION ===") + "\n")
results = d.get("results", {})
for acct, r in results.items():
if r.get("ok"):
files_str = ", ".join(u.get("file") for u in r.get("updates", []))
print(c_green(f" ✓ {acct.upper():6} drive injected ({files_str})"))
else:
print(c_red(f" ✗ {acct.upper():6} failed: {r.get('error')}"))
print(f"\n{c_green('✓ Fleet synchronization complete.')}\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_amend(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md", "amend", args.filename]
if args.file:
cmd.extend(["--file", args.file])
elif args.content:
cmd.extend(["--content", args.content])
if args.author:
cmd.extend(["--author", args.author])
if args.reason:
cmd.extend(["--reason", args.reason])
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
commit_info = f" (git commit: {d.get('commit')})" if d.get("commit") else ""
print(c_green(f"\n✓ Successfully amended shared/operators/{args.filename}{commit_info}"))
print(f" Author: {c_cyan(d.get('author'))}")
print(f" Bytes: {d.get('bytes_written')}\n")
print(c_dim(" Broadcast to fleet with: box md sync-all\n"))
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_append(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md", "append", args.filename, args.text]
if args.author:
cmd.extend(["--author", args.author])
if args.section:
cmd.extend(["--section", args.section])
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
commit_info = f" (git commit: {d.get('commit')})" if d.get("commit") else ""
print(c_green(f"\n✓ Successfully appended note to shared/operators/{args.filename}{commit_info}"))
print(f" Author: {c_cyan(d.get('author'))}\n")
print(c_dim(" Broadcast to fleet with: box md sync-all\n"))
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_pull(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "md", "pull", args.account, args.filename]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print(c_green(f"✓ Pulled canonical shared/operators/{args.filename} into {args.account} container ({d.get('bytes_written')} B)"))
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_md_watchdog(args):
watchdog_py = BIN_DIR / "agent-drive-watchdog.py"
if args.sub_action == "status":
cmd = ["python3", str(watchdog_py), "--status"]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
print("\n" + c_bold("=== NETVM FLEET AGENT DRIVE WATCHDOG STATUS ===") + "\n")
print(f" Last Run: {c_cyan(d.get('last_run', 'never'))}")
st = d.get("agent_status", {})
headers = ["AGENT", "DRIVE SCORE", "STATUS", "LAST CHECKED", "ISSUES"]
rows = []
for acct, info in st.items():
score = info.get("score", 0)
score_str = c_green(f"{score}/100") if score == 100 else c_red(f"{score}/100")
stat = c_green("HIGH DRIVE") if info.get("status") == "HIGH_DRIVE" else c_red(info.get("status", "DEGRADED"))
dt = (info.get("last_checked") or "-")[:19]
iss = ", ".join(info.get("issues", [])) or c_dim("none")
rows.append([c_bold(acct.upper()), score_str, stat, dt, iss])
print_table(headers, rows)
# Show timer status
tr = subprocess.run(["systemctl", "--user", "is-active", "agent-drive-watchdog.timer"], capture_output=True, text=True)
t_stat = tr.stdout.strip()
t_badge = c_green("ACTIVE (every 10m)") if t_stat == "active" else c_yellow(t_stat)
print(f"\n Systemd Timer: {t_badge}\n")
except Exception:
sys.stdout.write(res.stdout)
elif args.sub_action == "run":
cmd = ["python3", str(watchdog_py), "--once"]
if getattr(args, "no_heal", False):
cmd.append("--no-heal")
print("\n" + c_bold("=== RUNNING FLEET AGENT DRIVE WATCHDOG CYCLE ===") + "\n")
subprocess.run(cmd)
print()
else:
print("Usage: box md watchdog {status|run}")
def cmd_swarm_list(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "swarm-list"]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
swarms = d.get("swarms", [])
print("\n" + c_bold(f"=== SWARMS ({len(swarms)}) ===") + "\n")
headers = ["ID", "STATUS", "LABEL", "TOTAL", "DONE", "RUNNING", "FAILED", "CREATED"]
rows = []
for sw in swarms:
st = sw.get("status")
st_color = c_green(st) if st == "completed" else (c_yellow(st) if st in ("running", "partial") else c_dim(st))
rows.append([
c_cyan(sw.get("swarm_id", "")[:18]),
st_color,
(sw.get("label") or "-")[:20],
str(sw.get("count", 0)),
str(sw.get("done", 0)),
str(sw.get("running", 0)),
str(sw.get("failed", 0)),
(sw.get("created_ts") or "")[:16]
])
print_table(headers, rows)
print("\n" + c_dim(" Spawn swarm: box swarm spawn <count> <task> [--label L]") + "\n")
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_swarm_status(args):
sid = args.swarm_id
if not sid.startswith("sw-"):
sid = "sw-" + sid
# Support prefix matching if exact ID is truncated (e.g. 18 chars)
sw_file = Path(__file__).resolve().parent.parent / "swarms.json"
if sw_file.exists():
try:
import json
data = json.loads(sw_file.read_text(encoding="utf-8"))
if sid not in data:
matches = [k for k in data.keys() if k.startswith(sid)]
if len(matches) == 1:
sid = matches[0]
except Exception:
pass
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "swarm-status", sid]
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print(c_bold(f"\n=== SWARM STATUS: {args.swarm_id} ==="))
sw = d.get("swarm", {})
print(f" Status: {sw.get('status')}")
print(f" Counts: {d.get('counts')}")
slots = sw.get("slots", [])
print(f"\n Slots ({len(slots)}):")
for s in slots:
res_txt = s.get("result")
res_prev = (str(res_txt)[:50] + "...") if res_txt and len(str(res_txt)) > 50 else str(res_txt)
print(f" Slot {s.get('slot')}: [{s.get('status')}] agent={s.get('agent_id')} subagent={s.get('subagent_session_id')} res={res_prev}")
print()
else:
print(c_red(f"✗ Failed: {d.get('error')}"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_swarm_spawn(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "swarm-spawn", str(args.count), args.task]
if args.label:
cmd.extend(["--label", args.label])
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print(c_green(f"✓ Spawned swarm: {d.get('swarm_id')} ({d.get('count')} slots)"))
else:
print(c_red(f"✗ Failed: {d.get('error')} ({d.get('code')})"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_swarm_prune(args):
cmd = ["python3", str(BIN_DIR / "box-ctl.py"), "swarm-prune", "--stale-hours", str(args.stale_hours)]
if args.confirm:
cmd.append("--confirm")
res = subprocess.run(cmd, capture_output=True, text=True)
if args.json:
sys.stdout.write(res.stdout)
return
try:
d = json.loads(res.stdout)
if d.get("ok"):
print(c_green(f"✓ Pruned {d.get('archived_count')} swarms older than {d.get('stale_hours')}h to 'archived'"))
else:
print(c_yellow(f"! {d.get('error')} (use --confirm)"))
except Exception:
sys.stdout.write(res.stdout)
def cmd_passkey_info(args):
"""Display operator passkey reference and agent approval architecture, or fetch from VM."""
action = getattr(args, "action", "show") or "show"
is_json = getattr(args, "json", False)
if action in ("fetch", "get"):
vm_host = "34.139.37.135"
vm_paths = ["/srv/box/passkey.txt", "/etc/netvm/passkey.txt"]
cmd = [
"ssh",
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=3",
f"super@{vm_host}",
f"cat {vm_paths[0]} 2>/dev/null || cat {vm_paths[1]} 2>/dev/null"
]
key_content = ""
fetch_err = None
try:
res = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
if res.returncode == 0 and res.stdout.strip():
key_content = res.stdout.strip()
else:
fetch_err = res.stderr.strip() or "Empty output or authentication required"
except subprocess.TimeoutExpired:
fetch_err = "SSH connection timed out"
except Exception as e:
fetch_err = str(e)
if key_content:
if is_json:
print(json.dumps({
"ok": True,
"fetched": True,
"passkey": key_content,
"vm_host": vm_host,
"path": vm_paths[0],
"operator_pin": "3128",
"surface": "https://box.muse-dev.online/"
}, indent=2))
return
print("\n" + c_bold("=== OPERATOR PASSKEY (FETCHED FROM VM) ===") + "\n")
print(f" {c_bold('Passkey Content')}: {c_green(key_content)}")
print(f" {c_bold('Source Host')} : {c_cyan(vm_host)} ({vm_paths[0]})")
print(f" {c_bold('Web Surface')} : https://box.muse-dev.online/ (PIN: 3128)\n")
return
else:
if is_json:
print(json.dumps({
"ok": False,
"fetched": False,
"vm_host": vm_host,
"path": vm_paths[0],
"fallback_path": vm_paths[1],
"operator_pin": "3128",
"surface": "https://box.muse-dev.online/",
"error": f"Could not fetch passkey directly: {fetch_err}",
"note": "Passkey is stored in a single .txt file on the VM (34.139.37.135) only, NOT on BL (100.123.153.75).",
"operator_command": f"ssh super@{vm_host} 'cat {vm_paths[0]}'",
"agent_approval_command": "box approvals request-key <node> --reason '<reason>'"
}, indent=2))
return
print("\n" + c_bold("=== VM PASSKEY FETCH PROBE ===") + "\n")
print(f" {c_bold('Target VM Host')} : {c_cyan(vm_host)}")
print(f" {c_bold('Target Paths')} : {vm_paths[0]} (fallback: {vm_paths[1]})")
print(f" {c_bold('Probe Result')} : {c_yellow('Direct SSH access unavailable (' + (fetch_err or 'auth required') + ')')}\n")
print(c_bold(" Location Reality (VM vs BL):"))
print(f" • {c_yellow('VM (' + vm_host + ')')} : Key material lives in a {c_bold('single text file (.txt)')} on the VM.")
print(f" • {c_red('BL (100.123.153.75)')} : {c_bold('NO passkey / secret material exists on the dedicated BL.')}\n")
print(f" {c_bold('Console PIN')} : {c_green('3128')} (sets session cookie: {c_dim('ops_session')} at {c_cyan('https://box.muse-dev.online/')})\n")
print(c_bold(" Operator Access:"))
print(f" ssh super@{vm_host} 'cat {vm_paths[0]}'\n")
print(c_bold(" Agent UX / Approval Request:"))
print(f" Agents must not hunt BL. If passkey authorization is needed, request it via:")
print(f" {c_cyan('box approvals request-key <node> --reason \"<reason>\"')}\n")
return
if is_json:
print(json.dumps({
"ok": True,
"surface": "https://box.muse-dev.online/",
"operator_pin": "3128",
"session_cookie": "ops_session",
"key_location": {
"host": "Google Cloud VM (34.139.37.135)",
"canonical_path": "/srv/box/passkey.txt",
"fallback_path": "/etc/netvm/passkey.txt",
"note": "Stored in a single text file (.txt) on the VM — NOT on the dedicated BL compute node (100.123.153.75)",
"credstore_path": "/etc/netvm/meta-credentials/store.age",
"credstore_key": "/etc/netvm/meta-credentials/.age-key"
},
"operator_fetch_cmd": "ssh super@34.139.37.135 'cat /srv/box/passkey.txt'",
"agent_approval_protocol": {
"rule": "Agents do not hold administrative passkeys or credentials directly. Secrets never reside on bl.",
"request_flow": "1. Agent signals APPROVAL_REQUEST: key=<reason> or runs 'box approvals request-key <node>'.\n2. Operator verifies request.\n3. Operator retrieves key/PIN from VM single text file (.txt) or submits OTP.\n4. Operator approves via 'box approvals allow <node>'.",
"request_command": "box approvals request-key <node> --reason '<reason>'",
"sidechats": ["646 tasks", "pip tasks", "#jobs", "heartbeat"]
}
}, indent=2))
return
print("\n" + c_bold("=== OPERATOR PASSKEY & KEY MATERIAL ARCHITECTURE ===") + "\n")
print(f" {c_bold('Box Front-Door Console')}: {c_cyan('https://box.muse-dev.online/')}")
print(f" {c_bold('Operator PIN / Passkey')}: {c_green('3128')} (sets session cookie: {c_dim('ops_session')})\n")
print(c_bold(" Location Reality (VM vs BL):"))
print(f" • {c_yellow('VM (34.139.37.135)')} : Key material lives in a {c_bold('single text file (.txt)')} on the VM.")
print(f" - Canonical path: {c_cyan('/srv/box/passkey.txt')}")
print(f" - Fallback path : {c_cyan('/etc/netvm/passkey.txt')}")
print(f" - Fetch command : {c_dim('box passkey fetch')}")
print(f" • {c_red('BL (100.123.153.75)')} : {c_bold('NO passkey / secret material exists on the dedicated BL.')}")
print(f" • Credstore on VM : /etc/netvm/meta-credentials/store.age (age-encrypted, root 600)")
print(f" • Age Key on VM : /etc/netvm/meta-credentials/.age-key\n")
print(c_bold(" Agent UX & Operator Approval Flow:"))
print(f" 1. {c_cyan('Never hunt on bl')} : Agents must never attempt to grep or locate passkeys on bl.")
print(f" 2. {c_cyan('Signal Approval')} : If an agent requires key access or operator privilege:")
print(f" - Run: {c_yellow('box approvals request-key <node> --reason \"<reason>\"')}")
print(f" - Or emit {c_yellow('APPROVAL_NEEDED: <details>')} in task sidechat")
print(f" - Or exit with code {c_yellow('2')} (per INFRA.md convention)")
print(f" 3. {c_cyan('Operator Action')} : Operator consults the single .txt file on the VM to authenticate")
print(f" and approves via {c_dim('box approvals allow <node>')}.")
print(f" 4. {c_cyan('Target Sidechats')} : Use dedicated sidechats ({c_dim('646 tasks, pip tasks, #jobs, heartbeat')}).\n")
def _lookup_unreads(args):
data = collect_fleet_data()
as_json = getattr(args, "json", False)
if as_json:
nodes_out = []
for item in data:
n = item.get("node")
title = item.get("title", "")
unread_cnt = 0
if "(1)" in title or "(2)" in title or "(3)" in title:
m = re.search(r"\((\d+)\)", title)
unread_cnt = int(m.group(1)) if m else 1
thread_info = "-"
if "thread/" in item.get("url", ""):
thread_info = item["url"].split("thread/")[-1][:12]
elif item.get("url") == "https://muse.ai/":
thread_info = "home"
nodes_out.append({
"node": n,
"unread": unread_cnt,
"title": title,
"thread": thread_info,
"approval_pending": bool(item.get("approval_pending")),
})
print(json.dumps({"ok": True, "nodes": nodes_out}))
return
print("\n" + c_bold("=== FLEET UNREAD / ACTIVITY STATUS ===") + "\n")
headers = ["NODE", "UNREAD COUNT", "ACTIVE PAGE / TITLE", "LAST SEEN / THREAD"]
rows = []
for item in data:
n = item["node"]
title = item.get("title", "")
unread = "0"
if "(1)" in title or "(2)" in title or "(3)" in title:
m = re.search(r"\((\d+)\)", title)
unread = c_yellow(m.group(1)) if m else c_yellow("1+")
elif item.get("approval_pending"):
unread = c_yellow("APPROVAL")
thread_info = "-"
if "thread/" in item.get("url", ""):
thread_info = item["url"].split("thread/")[-1][:12]
elif item.get("url") == "https://muse.ai/":
thread_info = "home"
rows.append([c_bold(n), unread, title[:45], thread_info])
print_table(headers, rows)
print("\n" + c_dim(" To view unread messages: box thread view <node> <thread>") + "\n")
def cmd_lookup(args):
"""Seamless unified lookup across nodes, threads, unreads, approvals, and keys."""
lookup_args = getattr(args, "lookup_args", []) or []
if "--json" in lookup_args:
setattr(args, "json", True)
sub = getattr(args, "target", None)
if not sub or sub in ("all", "summary"):
print("\n" + c_bold("=== SEAMLESS FLEET LOOKUP SUMMARY ===") + c_dim(f" ({datetime.now().strftime('%H:%M:%S')} local)\n"))
# 1. Fleet status
cmd_fleet_status(args)
# 2. Approvals summary
try:
import approvals
app_list = approvals.check_fleet_approvals(VALID_NODES)
pending = [a for a in app_list if a.get("status") == "PENDING"]
if pending:
print(c_yellow(f" ⚠ {len(pending)} pending approval(s): {', '.join(a['node'] for a in pending)} (run: box approvals)"))
else:
print(c_green(" ✔ Approval Queues: All clean"))
except Exception:
pass
# 3. Key note
print(c_dim(" ℹ Passkey: Stored in single .txt on VM (34.139.37.135), not bl. (run: box passkey)"))
print()
return
if sub in ("key", "passkey", "auth"):
cmd_passkey_info(args)
elif sub in ("fleet", "nodes"):
cmd_fleet_status(args)
elif sub in ("threads", "sidechats"):
cmd_thread_list(args)
elif sub in ("unread", "unreads"):
_lookup_unreads(args)
elif sub in ("approvals", "approval"):
cmd_approvals(args)
elif sub in ("docs", "doc", "surfaces", "sentence", "regex", "parse"):
extra = getattr(args, "lookup_args", []) or []
sub_args = [sub] if sub not in ("docs", "doc") else []
cmd = [sys.executable, str(BIN_DIR / "docs-lookup.py")] + sub_args + extra
res = subprocess.run(cmd)
sys.exit(res.returncode)
else:
print(f"Unknown lookup target '{sub}'. Choose from: fleet, threads, unread, approvals, key, docs", file=sys.stderr)
def _sanitize_tmux_name(name: str) -> str:
cleaned = re.sub(r"[^a-zA-Z0-9_-]", "-", name).strip("-")
cleaned = re.sub(r"-+", "-", cleaned)
return cleaned or "run"
def _write_watch_script(session: str) -> tuple[str, str]:
watch_session = f"{session}-watch"
script_path = f"/tmp/{watch_session}.sh"
content = f"""#!/bin/bash
target="{session}"
exit_file="/tmp/{session}.exit"
max=200
count=0
while [ $count -lt $max ]; do
if ! tmux -S /tmp/tmux-muse.sock has-session -t "$target" 2>/dev/null; then
break
fi
pane_content=$(tmux -S /tmp/tmux-muse.sock capture-pane -p -t "$target" 2>/dev/null)
if echo "$pane_content" | grep -q "› 1. Yes, proceed"; then
tmux -S /tmp/tmux-muse.sock send-keys -t "$target" "1" Enter
fi
sleep 1
count=$((count+1))
done
touch "$exit_file"
"""
p = Path(script_path)
p.write_text(content, encoding="utf-8")
os.chmod(script_path, 0o755)
return watch_session, script_path
def cmd_run(args):
"""Run a headless muse-code session in tmux on /tmp/tmux-muse.sock."""
if not shutil.which("tmux"):
print("tmux not found", file=sys.stderr)
sys.exit(2)
if not shutil.which("muse-code"):
print("muse-code not found", file=sys.stderr)
sys.exit(2)
prompt = getattr(args, "prompt", None)
prompt_file = getattr(args, "prompt_file", None)
if not prompt and not prompt_file:
if sys.stdin.isatty():
print("Error: prompt or --prompt-file required", file=sys.stderr)
sys.exit(2)
prompt = sys.stdin.read()
if not prompt.strip():
print("Error: empty prompt", file=sys.stderr)
sys.exit(2)
raw_session = getattr(args, "session", None) or f"run-{int(time.time())}"
session = _sanitize_tmux_name(raw_session)
auto_approve = getattr(args, "auto_approve", False)
prompt_path = f"/tmp/{session}.prompt"
if prompt:
Path(prompt_path).write_text(prompt if prompt.endswith("\n") else prompt + "\n", encoding="utf-8")
elif prompt_file:
prompt_path = prompt_file
wrapper_path = f"/tmp/{session}.sh"
cmd_parts = [
"cd /home/super/Projects/NetVM",
f"muse-code --prompt-file {prompt_path}",
]
if getattr(args, "provider", None):
cmd_parts.append(f"--provider {args.provider}")
if getattr(args, "model", None):
cmd_parts.append(f"--model {args.model}")
if getattr(args, "effort", None):
cmd_parts.append(f"--reasoning-effort {args.effort}")
if getattr(args, "permission_profile", None):
cmd_parts.append(f"--permission-profile {args.permission_profile}")
if getattr(args, "trust_workspace", False):
cmd_parts.append("--trust-workspace")
if getattr(args, "approval_mode", None):
cmd_parts.append(f"--approval-mode {args.approval_mode}")
full_cmd = " && ".join(cmd_parts)
wrapper_content = f"#!/bin/bash\n{full_cmd}\ntouch /tmp/{session}.exit\n"
Path(wrapper_path).write_text(wrapper_content, encoding="utf-8")
os.chmod(wrapper_path, 0o755)
MUSE_TMUX_LOG_DIR.mkdir(parents=True, exist_ok=True)
log_path = MUSE_TMUX_LOG_DIR / f"{session}.log"
tmux_cmd = [
"tmux", "-S", "/tmp/tmux-muse.sock",
"new-session", "-d", "-s", session,
f"{wrapper_path} 2>&1 | tee {log_path}"
]
res = subprocess.run(tmux_cmd)
if res.returncode != 0:
print(f"Error launching tmux session: {res.stderr or 'failed'}", file=sys.stderr)
sys.exit(res.returncode or 1)
print(f"session: {session}")
print(f"attach: tmux -S /tmp/tmux-muse.sock attach -t {session}")
if auto_approve:
watch_session, watch_script = _write_watch_script(session)
watch_log = MUSE_TMUX_LOG_DIR / f"{watch_session}.log"
w_cmd = [
"tmux", "-S", "/tmp/tmux-muse.sock",
"new-session", "-d", "-s", watch_session,
f"{watch_script} 2>&1 | tee {watch_log}"
]
w_res = subprocess.run(w_cmd)
if w_res.returncode == 0:
print(f"watcher: {watch_session}")
print(f"watcher-log: {watch_log}")
def cmd_watch(args):
"""Spawn an auto-approve watcher on an existing tmux session."""
if not shutil.which("tmux"):
print("tmux not found", file=sys.stderr)
sys.exit(2)
raw_session = getattr(args, "session", None)
if not raw_session:
print("Error: session name required", file=sys.stderr)
sys.exit(2)
session = _sanitize_tmux_name(raw_session)
has_res = subprocess.run(["tmux", "-S", "/tmp/tmux-muse.sock", "has-session", "-t", session])
if has_res.returncode != 0:
print(f"Error: session '{session}' does not exist", file=sys.stderr)
sys.exit(2)
watch_session, watch_script = _write_watch_script(session)
MUSE_TMUX_LOG_DIR.mkdir(parents=True, exist_ok=True)
watch_log = MUSE_TMUX_LOG_DIR / f"{watch_session}.log"
w_cmd = [
"tmux", "-S", "/tmp/tmux-muse.sock",
"new-session", "-d", "-s", watch_session,
f"{watch_script} 2>&1 | tee {watch_log}"
]
w_res = subprocess.run(w_cmd)
if w_res.returncode != 0:
print(f"Error starting watcher: {w_res.stderr or 'failed'}", file=sys.stderr)
sys.exit(w_res.returncode or 1)
print(f"watching: {session}")
print(f"watcher: {watch_session}")
print(f"watcher-log: {watch_log}")
def cmd_docs_dispatch(args):
"""Bridge 'box docs' and 'super docs' directly to bin/docs-lookup.py."""
d_args = getattr(args, "docs_args", []) or []
cmd = [sys.executable, str(BIN_DIR / "docs-lookup.py")] + d_args
res = subprocess.run(cmd)
sys.exit(res.returncode)
def cmd_tmux_dispatch(args):
"""Bridge 'box tmux' commands directly to bin/muse-tmux.py or tmux_auto_approver.py."""
t_args = getattr(args, "tmux_args", []) or []
if t_args and t_args[0] in ("tally", "auto", "watch", "once", "match", "rules", "status"):
approver_bin = str(BIN_DIR / "tmux_auto_approver.py")
if t_args[0] == "auto":
sub = t_args[1:] or ["status"]
else:
sub = t_args
cmd = [sys.executable, approver_bin] + sub
res = subprocess.run(cmd)
sys.exit(res.returncode)
tmux_bin = str(BIN_DIR / "muse-tmux.py")
if not t_args:
t_args = ["list"]
cmd = [sys.executable, tmux_bin] + t_args
res = subprocess.run(cmd)
sys.exit(res.returncode)
def cmd_flow_dispatch(args):
"""Bridge 'box flow' commands directly to bin/flow_engine.py."""
flow_bin = str(BIN_DIR / "flow_engine.py")
f_args = getattr(args, "flow_args", []) or []
cmd = [sys.executable, flow_bin] + f_args
res = subprocess.run(cmd)
sys.exit(res.returncode)
def cmd_muse_dispatch(args):
"""Bridge 'box muse' commands to muse-cli-node or interactive REPL / multi-node lookups."""
m_args = getattr(args, "muse_args", []) or []
if not m_args:
cmd = [str(BIN_DIR / "muse"), "--help"]
res = subprocess.run(cmd)
sys.exit(res.returncode)
first = m_args[0]
# If first is 'tmux', dispatch to tmux
if first == "tmux":
cmd = [sys.executable, str(BIN_DIR / "muse-tmux.py")] + m_args[1:]
res = subprocess.run(cmd)
sys.exit(res.returncode)
# If first is a cross-fleet query
if first in ("status", "fleet"):
cmd_fleet_status(args)
return
if first in ("passkey", "key"):
cmd_passkey_info(args)
return
if first in ("lookup", "lookups"):
setattr(args, "target", m_args[1] if len(m_args) > 1 else None)
cmd_lookup(args)
return
if first in ("threads", "sidechats"):
cmd_thread_list(args)
return
if first in ("unread", "unreads"):
_lookup_unreads(args)
return
# If first is a valid node
if first in VALID_NODES:
node = first
subargs = m_args[1:]
if not subargs:
subargs = ["status"]
if subargs[0] == "chat":
cmd = [sys.executable, str(BIN_DIR / "muse-chat-repl.py"), node] + subargs[1:]
res = subprocess.run(cmd)
sys.exit(res.returncode)
cmd = [str(BIN_DIR / "muse-cli-node"), node] + subargs
res = subprocess.run(cmd)
sys.exit(res.returncode)
# Fallback to bin/muse wrapper
cmd = [str(BIN_DIR / "muse")] + m_args
res = subprocess.run(cmd)
sys.exit(res.returncode)
# ---------------------------------------------------------------------------
# Domain: SYSOP (one-shot fleet installer)
# ---------------------------------------------------------------------------
SYSOP_SYSTEMD_DIR = NETVM_ROOT / "systemd"
# `systemctl show -p NextElapseUSecRealtime --value` reports this when a
# timer has no computed next elapse (UINT64_MAX = USEC_INFINITY).
SYSOP_NO_NEXT = {"", "0", "n/a", "18446744073709551615"}
def sysop_user_units_dir():
return Path.home() / ".config" / "systemd" / "user"
def sysop_unit_files(systemd_dir=None):
"""Sorted unit filenames (*.timer + *.service) shipped in systemd/."""
d = Path(systemd_dir) if systemd_dir else SYSOP_SYSTEMD_DIR
if not d.is_dir():
return []
return sorted(p.name for p in d.iterdir()
if p.is_file() and p.suffix in (".timer", ".service"))
def sysop_timer_needs_anchor(timer_path):
"""True when a timer uses relative triggers (OnBootSec/OnActiveSec/
OnUnitActiveSec) whose NEXT stays empty until the service runs once."""
try:
text = Path(timer_path).read_text()
except OSError:
return False
return any(k in text for k in ("OnUnitActiveSec=", "OnBootSec=",
"OnActiveSec="))
def sysop_is_daemon(service_path):
"""True for long-lived daemons that must not be one-shot started."""
try:
text = Path(service_path).read_text()
except OSError:
return False
return "Restart=always" in text
def _sysop_next(run, timer):
"""NEXT elapse for a timer, or None when absent/unparseable."""
rc, out = run(["systemctl", "--user", "show", timer,
"-p", "NextElapseUSecRealtime", "--value"])
nxt = (out or "").strip()
if rc == 0 and nxt not in SYSOP_NO_NEXT:
return nxt
return None
def _sysop_service_state(run, service):
"""ActiveState for a service ('' when unknown)."""
rc, out = run(["systemctl", "--user", "show", service,
"-p", "ActiveState", "--value"])
return (out or "").strip() if rc == 0 else ""
def sysop_install_units(systemd_dir=None, user_dir=None, dry_run=False,
run=None, progress=None, anchor_timeout=90,
poll_interval=3):
"""Link fleet units, reload, enable timers, anchor + verify them.
Returns a result dict with per-unit reports and a failures list.
Idempotent: correct symlinks are kept, systemctl calls are re-runnable.
With dry_run=True nothing is changed and no command is executed.
progress, when given, is called with short status lines as work
happens (the run is otherwise silent for minutes behind slow
service starts). Anchors never block indefinitely: services are
started --no-block and NEXT is polled up to anchor_timeout; a
still-activating service is reported in-progress (it self-anchors
on completion) rather than failed.
"""
run = run or _sh
say = progress or (lambda line: None)
src_dir = Path(systemd_dir) if systemd_dir else SYSOP_SYSTEMD_DIR
dst_dir = Path(user_dir) if user_dir else sysop_user_units_dir()
units = sysop_unit_files(src_dir)
timers = [u for u in units if u.endswith(".timer")]
services = {u for u in units if u.endswith(".service")}
result = {"ok": True, "dry_run": dry_run, "units": [],
"daemon_reload": {"ok": True, "detail": ""},
"timers": [], "failures": []}
def fail(msg):
result["failures"].append(msg)
result["ok"] = False
if not timers:
fail("no *.timer units discovered in %s" % src_dir)
return result
# (1) Symlink every shipped unit into the user systemd dir.
if not dry_run:
try:
dst_dir.mkdir(parents=True, exist_ok=True)
except OSError as e:
fail("cannot create %s: %s" % (dst_dir, e))
return result
for name in units:
src = src_dir / name
dst = dst_dir / name
if dry_run:
result["units"].append(
{"unit": name, "status": "would-link",
"src": str(src), "dst": str(dst)})
continue
try:
if dst.is_symlink() and dst.resolve() == src.resolve():
result["units"].append(
{"unit": name, "status": "already-linked",
"dst": str(dst)})
continue
if dst.is_symlink() or dst.exists():
dst.unlink()
dst.symlink_to(src)
result["units"].append(
{"unit": name, "status": "linked", "dst": str(dst)})
except OSError as e:
result["units"].append(
{"unit": name, "status": "failed", "error": str(e)})
fail("link %s: %s" % (name, e))
if dry_run:
for timer in timers:
result["timers"].append(
{"timer": timer, "enabled": None, "anchored": None,
"anchor_skipped": None, "next": None,
"note": "would enable --now, anchor, and verify"})
return result
# (2) Reload the user manager.
say("daemon-reload ...")
rc, out = run(["systemctl", "--user", "daemon-reload"])
result["daemon_reload"] = {"ok": rc == 0, "detail": out}
if rc != 0:
fail("daemon-reload: %s" % (out or ("exit %d" % rc)))
# (3)-(5) Enable, anchor, and verify each timer.
for timer in timers:
entry = {"timer": timer, "enabled": False, "anchored": False,
"anchor_skipped": None, "next": None, "note": None}
say("enable --now %s ..." % timer)
rc, out = run(["systemctl", "--user", "enable", "--now", timer])
entry["enabled"] = rc == 0
if rc != 0:
fail("enable --now %s: %s" % (timer, out or ("exit %d" % rc)))
# (4) Anchor relative timers: start the matching oneshot
# service once so OnUnitActiveSec gains a reference timestamp
# (fresh-install-mid-boot otherwise leaves NEXT empty). The
# start is --no-block: slow first runs (backlog scrapes)
# would otherwise stall the whole install with no output.
service = timer[:-len(".timer")] + ".service"
if service not in services:
entry["anchor_skipped"] = "no matching service shipped"
elif not sysop_timer_needs_anchor(src_dir / timer):
entry["anchor_skipped"] = "calendar timer needs no anchor"
elif sysop_is_daemon(src_dir / service):
entry["anchor_skipped"] = "long-lived daemon, not started"
else:
state = _sysop_service_state(run, service)
if state == "activating":
say("anchor %s: already running, waiting for NEXT ..."
% service)
else:
say("anchor %s: starting ..." % service)
rc, out = run(["systemctl", "--user", "start",
"--no-block", service])
if rc != 0:
fail("start %s: %s"
% (service, out or ("exit %d" % rc)))
state = "start-failed"
# (5) Poll for a real NEXT elapse (bounded).
if state != "start-failed":
polled = _sysop_poll_next(
run, say, timer, service, anchor_timeout,
poll_interval)
msg = polled.pop("_fail", None)
if msg:
fail(msg)
entry.update(polled)
# Timers whose anchor was skipped still get one NEXT check.
if entry["anchor_skipped"] and entry["next"] is None:
nxt = _sysop_next(run, timer)
if nxt is not None:
entry["next"] = nxt
else:
fail("verify %s: no NEXT elapse" % timer)
result["timers"].append(entry)
return result
def _sysop_poll_next(run, say, timer, service, timeout, interval):
"""Poll until the timer shows NEXT, the service fails, or timeout.
Returns a partial timer entry (anchored/next/note). A service
still activating at timeout is reported in-progress rather than
failed: its running start job anchors the timer on completion.
"""
deadline = time.monotonic() + max(0, timeout)
while True:
nxt = _sysop_next(run, timer)
if nxt is not None:
return {"anchored": True, "next": nxt, "note": None}
state = _sysop_service_state(run, service)
if state == "failed":
return {"anchored": False, "next": None,
"note": None, "_fail":
"anchor %s: service failed "
"(journalctl --user -u %s)" % (service, service)}
if time.monotonic() >= deadline:
if state == "activating":
say("anchor %s: still running, timer self-anchors "
"on completion" % service)
return {"anchored": "in-progress", "next": None,
"note": "anchor running; verify NEXT shortly"}
return {"anchored": False, "next": None,
"note": None, "_fail":
"verify %s: no NEXT elapse "
"(service state: %s)" % (timer, state or "?")}
say("anchor %s: waiting for NEXT ..." % service)
time.sleep(max(0, interval))
def cmd_sysop_install(args):
dry_run = getattr(args, "dry_run", False)
as_json = getattr(args, "json", False)
# Live progress: stdout in text mode, stderr in --json mode so
# stdout stays pure machine-readable JSON.
progress = (lambda line: print(" ... %s" % line, flush=True,
file=sys.stderr if as_json else sys.stdout))
result = sysop_install_units(dry_run=dry_run, progress=progress)
if as_json:
print(json.dumps(result, indent=2))
sys.exit(0 if result["ok"] else 1)
print(c_bold("\n=== SYSOP INSTALL%s ===\n" % (
" (dry-run)" if dry_run else "")))
for u in result["units"]:
st = u["status"]
mark = (badge_ok("LINKED") if st == "linked"
else badge_dim("KEPT") if st == "already-linked"
else c_cyan("○ WOULD-LINK") if st == "would-link"
else badge_err("FAILED"))
print(" %s %s" % (mark, u["unit"]))
if not dry_run:
dr = result["daemon_reload"]
print(" %s daemon-reload" % (
badge_ok("OK") if dr["ok"] else badge_err("FAILED")))
print()
for t in result["timers"]:
en = t["enabled"]
emark = (badge_dim("?") if en is None
else badge_ok("ON") if en else badge_err("OFF"))
if t.get("anchor_skipped"):
amark = c_dim("- %s" % t["anchor_skipped"])
elif t.get("anchored") == "in-progress":
amark = c_cyan("○ ANCHORING")
elif t["anchored"]:
amark = badge_ok("ANCHORED")
elif t["anchored"] is None:
amark = badge_dim("?")
else:
amark = badge_err("ANCHOR-FAILED")
nxt = (t["next"] or c_dim(t["note"]) if t.get("note")
else t["next"] or (c_dim("pending (dry-run)")
if dry_run else badge_err("NO NEXT")))
print(" %s %-32s %s NEXT=%s" % (emark, t["timer"], amark,
nxt))
print()
if result["failures"]:
for f in result["failures"]:
print(" %s %s" % (c_red("✘"), f))
print()
sys.exit(1)
print(" %s fleet units installed and verified.\n" % c_green("✔"))
sys.exit(0)
def build_parser():
common = argparse.ArgumentParser(add_help=False)
common.add_argument("--json", action="store_true", help="Output machine-readable JSON")
prog_name = Path(sys.argv[0]).name if sys.argv and sys.argv[0] else "super"
if prog_name.endswith(".py"):
prog_name = "super"
parser = argparse.ArgumentParser(
prog=prog_name,
description=f"{prog_name} — Unified Orchestrator CLI for NetVM & Box",
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[common]
)
subparsers = parser.add_subparsers(dest="domain", help="Orchestration Domain")
# Domain: FLEET
p_fleet = subparsers.add_parser("fleet", parents=[common], help="Node health, CDP status, active tabs, watch, restart, heal")
p_fleet.add_argument("action", nargs="?", default="status", choices=["status", "watch", "restart", "cdp", "heal"])
p_fleet.add_argument("node", nargs="?", default=None, help="Target node (for restart / cdp / heal)")
p_fleet.add_argument("--interval", type=int, default=2, help="Watch refresh interval in seconds")
# Domain: WATCHDOG
p_watchdog = subparsers.add_parser("watchdog", parents=[common], help="Watchdog timers: status, trigger runs")
p_watchdog.add_argument("action", nargs="?", default="status", choices=["status", "run"])
p_watchdog.add_argument("target", nargs="?", default=None, help="Target node (or 'relay') for run")
# Domain: APPROVALS
p_approvals = subparsers.add_parser("approvals", parents=[common], help="Inspect and handle agent browser & gateway approvals")
p_approval = subparsers.add_parser("approval", parents=[common], help="Alias for 'approvals'")
for p_app in (p_approvals, p_approval):
p_app.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
app_sub = p_app.add_subparsers(dest="app_action")
p_app_check = app_sub.add_parser("check", parents=[common], help="Check fleet approval states")
p_app_check.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_app_check.add_argument("-v", "--verbose", action="store_true", help="Show detailed task prompts, thread URLs, and card text")
p_app_list = app_sub.add_parser("list", parents=[common], help="Alias for 'check'")
p_app_list.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_app_list.add_argument("-v", "--verbose", action="store_true", help="Show detailed task prompts, thread URLs, and card text")
p_app_inspect = app_sub.add_parser("inspect", parents=[common], help="Inspect detailed approval and input-wait status on a node")
p_app_inspect.add_argument("node", choices=VALID_NODES, help="Target node to inspect")
p_app_allow = app_sub.add_parser("allow", parents=[common], help="Approve pending browser request")
p_app_allow.add_argument("node", choices=VALID_NODES, help="Target node to approve")
p_app_allow.add_argument("--always", action="store_true", help="Click 'Always allow this site' instead of 'Allow once'")
p_app_allow.add_argument("--force", action="store_true", help="Force approval even if target is untrusted")
p_app_allow.add_argument("--message", default=None, help="Optional message/credential to deliver to the waiting agent")
p_app_allow.add_argument("--allow-main-chat", action="store_true", help="Allow reply into Main Chat if agent is waiting there")
p_app_approve = app_sub.add_parser("approve", parents=[common], help="Alias for 'allow'")
p_app_approve.add_argument("node", choices=VALID_NODES, help="Target node to approve")
p_app_approve.add_argument("--always", action="store_true", help="Click 'Always allow this site' instead of 'Allow once'")
p_app_approve.add_argument("--force", action="store_true", help="Force approval even if target is untrusted")
p_app_approve.add_argument("--message", default=None, help="Optional message/credential to deliver to the waiting agent")
p_app_approve.add_argument("--allow-main-chat", action="store_true", help="Allow reply into Main Chat if agent is waiting there")
p_app_deny = app_sub.add_parser("deny", parents=[common], help="Deny pending browser request")
p_app_deny.add_argument("node", choices=VALID_NODES, help="Target node to deny")
p_app_deny.add_argument("--message", default=None, help="Optional message to deliver to the waiting agent")
p_app_deny.add_argument("--allow-main-chat", action="store_true", help="Allow reply into Main Chat if agent is waiting there")
p_app_auto = app_sub.add_parser("auto", parents=[common], help="Auto-approve all trusted requests across fleet")
p_app_auto.add_argument("--node", choices=VALID_NODES, default=None, help="Target node (or all nodes)")
p_app_watch = app_sub.add_parser("watch", parents=[common], help="Live watch pending approvals")
p_app_watch.add_argument("--interval", type=int, default=2, help="Watch refresh interval in seconds")
p_app_watch.add_argument("--auto", action="store_true", help="Automatically approve trusted requests as they appear")
p_app_watch.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_app_reply = app_sub.add_parser("reply", parents=[common], help="Reply to a waiting agent task/prompt in its active thread")
p_app_reply.add_argument("node", choices=VALID_NODES, help="Target node to reply to")
p_app_reply.add_argument("message", help="Message or answer to dispatch")
p_app_reply.add_argument("--allow-main-chat", action="store_true", help="Explicit override if the active thread is Main Chat")
p_app_dismiss = app_sub.add_parser("dismiss", parents=[common], help="Dismiss any open task dialog/popup on a node")
p_app_dismiss.add_argument("node", choices=VALID_NODES, help="Target node to dismiss dialog on")
p_app_clear = app_sub.add_parser("clear", parents=[common], help="Clear and dismiss pending input waits on a node or all nodes")
p_app_clear.add_argument("node", nargs="?", choices=VALID_NODES, default=None, help="Target node (or omit for all nodes)")
p_app_clear_all = app_sub.add_parser("clear-all", parents=[common], help="Clear and dismiss all pending input waits across fleet")
p_app_req_key = app_sub.add_parser("request-key", parents=[common], help="Request operator passkey/key approval for an agent")
p_app_req_key.add_argument("node", choices=VALID_NODES, help="Target node requesting key")
p_app_req_key.add_argument("--reason", default="Passkey authentication required", help="Reason for key request")
p_app_gates = app_sub.add_parser("gates", aliases=["gate"], parents=[common], help="Inspect coordinator decision record gates")
p_app_gates.add_argument("--scope", default=None, help="Check specific gate scope (e.g. role-layer, merges-to-main)")
# Domain: MUSE-CHOICES
p_mc = subparsers.add_parser("muse-choices", parents=[common], help="Muse TUI A/B/C choice auto-answer daemon (on/off/status/logs)")
mc_sub = p_mc.add_subparsers(dest="mc_action")
p_mc_on = mc_sub.add_parser("on", parents=[common], help="Enable auto-answers on all Muse panes")
p_mc_on.add_argument("--dry-run", action="store_true", help="Log answers instead of sending keys")
p_mc_off = mc_sub.add_parser("off", parents=[common], help="Disable auto-answers and stop all watchers")
p_mc_status = mc_sub.add_parser("status", parents=[common], help="Show desired state, watchers, recent answers")
p_mc_logs = mc_sub.add_parser("logs", parents=[common], help="Tail one pane watcher log")
p_mc_logs.add_argument("--socket", required=True, help="Tmux socket path (e.g. /tmp/tmux-1000/default)")
p_mc_logs.add_argument("--pane", required=True, help="Pane id (e.g. %%37)")
p_mc_logs.add_argument("-n", type=int, default=20, help="Lines to show (default: 20)")
p_mc_rec = mc_sub.add_parser("reconcile", parents=[common], help="Enforce desired state now (start missing / stop excess)")
p_mc_res = mc_sub.add_parser("resolve", parents=[common], help="Resolve a held prompt (approve now or deny it)")
p_mc_res.add_argument("--socket", required=True, help="Tmux socket path (e.g. /tmp/tmux-1000/default)")
p_mc_res.add_argument("--pane", required=True, help="Pane id (e.g. %%37)")
p_mc_res.add_argument("decision", choices=["approve", "deny"], help="Release the hold to approve, or deny it (permission kinds only)")
# Domain: RUNTIME
p_rt = subparsers.add_parser("runtime", parents=[common], help="Muse CLI tmux runtimes: list/send/launch/reconcile/kill/restart/brief")
rt_sub = p_rt.add_subparsers(dest="rt_action")
p_rt_list = rt_sub.add_parser("list", parents=[common], help="List panes with runtime state + approval posture (default)")
p_rt_list.add_argument("--socket", default=None, help="Only this tmux socket")
p_rt_list.add_argument("--muse-only", action="store_true", help="Only Muse CLI panes")
p_rt_send = rt_sub.add_parser("send", parents=[common], help="Send keys to a pane (reports pre-send state)")
p_rt_send.add_argument("--socket", default=None, help="Tmux socket (default: /tmp/tmux-1000/default)")
p_rt_send.add_argument("pane", help="Pane id (e.g. %%37)")
p_rt_send.add_argument("keys", help="Keys / text to send")
p_rt_send.add_argument("--no-enter", action="store_true", help="Do not send Enter after keys")
p_rt_open = rt_sub.add_parser("open", parents=[common], help="Attach to a session on a socket (execs tmux attach)")
p_rt_open.add_argument("--socket", default=None, help="Tmux socket (default: /tmp/tmux-1000/default)")
p_rt_open.add_argument("--session", default=None, help="Session name (default: the only session)")
p_rt_open.add_argument("--dry-run", action="store_true", help="Print the attach plan without attaching")
p_rt_launch = rt_sub.add_parser("launch", parents=[common], help="Launch a Muse session with approval trail injected (on-request)")
p_rt_launch.add_argument("--socket", default=None, help="Tmux socket (default: /tmp/tmux-muse.sock for Box fleet)")
p_rt_launch.add_argument("--session", required=True, help="New tmux session name")
p_rt_launch.add_argument("--window", "-w", default=None, help="Initial window name")
p_rt_launch.add_argument("--dry-run", action="store_true", help="Print the launch plan without creating")
p_rt_launch.add_argument("muse_args", nargs=argparse.REMAINDER, default=[], help="Extra muse args after --")
p_rt_layout = rt_sub.add_parser("layout", parents=[common], help="Show pane geometry vs approval minimums")
p_rt_layout.add_argument("--socket", default=None, help="Only this tmux socket")
p_rt_spread = rt_sub.add_parser("spread", parents=[common], help="Break squeezed runtimes into own windows")
p_rt_spread.add_argument("--socket", default=None, help="Only this tmux socket")
p_rt_spread.add_argument("--session", default=None, help="Only this tmux session")
p_rt_spread.add_argument("--dry-run", action="store_true", help="Print the spread plan without moving panes")
p_rt_rec = rt_sub.add_parser("reconcile", parents=[common], help="Enforce fleet/agents.json: relaunch missing, brief fresh panes, requeue stale claims")
p_rt_rec.add_argument("--manifest", default=None, help="Manifest path (default: fleet/agents.json)")
p_rt_rec.add_argument("--tasks", default=None, help="Task queue dir (default: alongside manifest)")
p_rt_rec.add_argument("--dry-run", action="store_true", help="Print the plan without changing anything")
p_rt_rec.add_argument("--adopt", action="store_true", help="Record live sessions as briefed without sending")
p_rt_kill = rt_sub.add_parser("kill", parents=[common], help="Kill a session on a socket")
p_rt_kill.add_argument("--socket", default=None, help="Tmux socket (default: /tmp/tmux-1000/default)")
p_rt_kill.add_argument("--session", required=True, help="Session name to kill")
p_rt_restart = rt_sub.add_parser("restart", parents=[common], help="Kill + relaunch + brief one manifest agent")
p_rt_restart.add_argument("--socket", default=None, help="Tmux socket (default: /tmp/tmux-1000/default)")
p_rt_restart.add_argument("--session", required=True, help="Manifest session name")
p_rt_restart.add_argument("--manifest", default=None, help="Manifest path (default: fleet/agents.json)")
p_rt_restart.add_argument("--dry-run", action="store_true", help="Print the plan without changing anything")
p_rt_brief = rt_sub.add_parser("brief", parents=[common], help="Send the manifest brief to a live idle pane")
p_rt_brief.add_argument("--socket", default=None, help="Tmux socket (default: /tmp/tmux-1000/default)")
p_rt_brief.add_argument("--session", required=True, help="Manifest session name")
p_rt_brief.add_argument("--manifest", default=None, help="Manifest path (default: fleet/agents.json)")
p_rt_brief.add_argument("--dry-run", action="store_true", help="Print the plan without changing anything")
p_work = subparsers.add_parser("work", parents=[common], help="Fleet workspace, task orchestration, worker scope, and active signals")
work_sub = p_work.add_subparsers(dest="work_action")
p_w_status = work_sub.add_parser("status", parents=[common], help="Show full operational work dashboard (default)")
p_w_start = work_sub.add_parser("start", parents=[common], help="Instantly start and assign new build ticket to an agent")
p_w_start.add_argument("title", help="Ticket title / summary")
p_w_start.add_argument("--to", dest="agent", required=True, help="Agent username (opm, 646, dev, pip, def, muse)")
p_w_start.add_argument("--goal", help="Optional detailed goal description")
p_w_assign = work_sub.add_parser("assign", parents=[common], help="Assign existing ticket to an agent")
p_w_assign.add_argument("issue", type=int, help="Issue number (e.g. 215)")
p_w_assign.add_argument("--to", dest="agent", required=True, help="Agent username")
p_w_merge = work_sub.add_parser("merge", parents=[common], help="Merge an open PR into master")
p_w_merge.add_argument("pr", type=int, help="Pull request number (e.g. 214)")
p_w_chats = work_sub.add_parser("chats", parents=[common], help="View recent live chat activity")
p_w_chats.add_argument("--agent", help="Filter by agent name")
p_w_chats.add_argument("--limit", type=int, default=10, help="Number of messages to show")
p_tasks = subparsers.add_parser("tasks", parents=[common], help="Agent work queue: pending/claimed/done files (distinct from scheduled jobs)")
p_tasks.add_argument("--dir", default=None, help="Task queue dir (default: fleet/tasks)")
tasks_sub = p_tasks.add_subparsers(dest="tasks_action")
p_t_list = tasks_sub.add_parser("list", parents=[common], help="List tasks across queues (default)")
p_t_list.add_argument("--dir", default=argparse.SUPPRESS, help="Task queue dir (default: fleet/tasks)")
p_t_list.add_argument("--queue", choices=["pending", "claimed", "done", "all"], default="all", help="Only this queue")
p_t_show = tasks_sub.add_parser("show", parents=[common], help="Print one task file")
p_t_show.add_argument("--dir", default=argparse.SUPPRESS, help="Task queue dir (default: fleet/tasks)")
p_t_show.add_argument("name", help="Task name (base or owner-suffixed)")
p_t_create = tasks_sub.add_parser("create", parents=[common], help="Write a new pending task from template")
p_t_create.add_argument("--dir", default=argparse.SUPPRESS, help="Task queue dir (default: fleet/tasks)")
p_t_create.add_argument("name", help="Task name like 012-slug.md")
p_t_create.add_argument("--title", required=True, help="Short title")
p_t_create.add_argument("--goal", required=True, help="Goal text")
p_t_create.add_argument("--steps", default="", help="Steps text")
p_t_create.add_argument("--dry-run", action="store_true", help="Print the plan without writing")
p_t_claim = tasks_sub.add_parser("claim", parents=[common], help="Atomically claim a pending task")
p_t_claim.add_argument("--dir", default=argparse.SUPPRESS, help="Task queue dir (default: fleet/tasks)")
p_t_claim.add_argument("name", help="Pending task name")
p_t_claim.add_argument("--as", dest="owner", required=True, help="Owner tmux session name")
p_t_claim.add_argument("--dry-run", action="store_true", help="Print the plan without moving")
p_t_done = tasks_sub.add_parser("done", parents=[common], help="Append notes and move a claim to done/")
p_t_done.add_argument("--dir", default=argparse.SUPPRESS, help="Task queue dir (default: fleet/tasks)")
p_t_done.add_argument("name", help="Claimed task name (base or suffixed)")
p_t_done.add_argument("--result", default="", help="Result notes to append")
p_t_done.add_argument("--dry-run", action="store_true", help="Print the plan without moving")
p_t_req = tasks_sub.add_parser("requeue", parents=[common], help="Move a claim back to pending/")
p_t_req.add_argument("--dir", default=argparse.SUPPRESS, help="Task queue dir (default: fleet/tasks)")
p_t_req.add_argument("name", help="Claimed task name (base or suffixed)")
p_t_req.add_argument("--dry-run", action="store_true", help="Print the plan without moving")
p_t_sweep = tasks_sub.add_parser("sweep", parents=[common], help="Requeue stale/dead-owner claims now")
p_t_sweep.add_argument("--dir", default=argparse.SUPPRESS, help="Task queue dir (default: fleet/tasks)")
p_t_sweep.add_argument("--manifest", default=None, help="Manifest path (default: fleet/agents.json)")
p_t_sweep.add_argument("--dry-run", action="store_true", help="Print the plan without moving")
# Domain: INVITE
p_invite = subparsers.add_parser("invite", parents=[common], help="Muse.ai invite codes: find per-agent codes and redeem")
p_invite.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node (status)")
inv_sub = p_invite.add_subparsers(dest="invite_action")
p_inv_status = inv_sub.add_parser("status", parents=[common], help="Invite code matrix across fleet (default)")
p_inv_status.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_inv_list = inv_sub.add_parser("list", parents=[common], help="Alias for 'status'")
p_inv_list.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_inv_code = inv_sub.add_parser("code", parents=[common], help="Show one agent's invite code")
p_inv_code.add_argument("node", choices=VALID_NODES, help="Target node")
p_inv_find = inv_sub.add_parser("find", parents=[common], help="Alias for 'code'")
p_inv_find.add_argument("node", choices=VALID_NODES, help="Target node")
p_inv_redeem = inv_sub.add_parser("redeem", parents=[common], help="Redeem an invite code on a node")
p_inv_redeem.add_argument("node", choices=VALID_NODES, help="Target node")
p_inv_redeem.add_argument("code", help="6-char invite code")
p_inv_redeem.add_argument("--method", choices=["auto", "dom", "api"], default="auto", help="Redemption method (default: auto)")
p_inv_redeem.add_argument("--notify", default=None, help="Sidechat to notify on loopback")
p_inv_redeem.add_argument("--notify-agent", default=None, help="Agent to notify on loopback")
p_inv_salvage = inv_sub.add_parser("salvage", parents=[common], help="Salvage an out-of-tokens agent (defaults to 646)")
p_inv_salvage.add_argument("node", nargs="?", default="646", choices=VALID_NODES, help="Blocked agent node (default: 646)")
p_inv_salvage.add_argument("--helper", choices=VALID_NODES, help="Specific helper agent to redeem code")
p_inv_salvage.add_argument("--notify", default=None, help="Sidechat to notify on loopback")
p_inv_salvage.add_argument("--notify-agent", default=None, help="Agent to notify on loopback")
# Domain: USAGE
p_usage = subparsers.add_parser("usage", parents=[common], help="Muse.ai usage limits per agent")
p_usage.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_usage.add_argument("node_pos", nargs="?", default=None, choices=VALID_NODES, help="Optional node positional argument")
# Domain: SETTINGS
p_settings = subparsers.add_parser("settings", parents=[common], help="Settings menu RPA automation")
settings_sub = p_settings.add_subparsers(dest="settings_action")
p_set_usage = settings_sub.add_parser("usage", parents=[common], help="Extract usage via Settings RPA")
p_set_usage.add_argument("node", choices=VALID_NODES, default="646", nargs="?", help="Target node (default: 646)")
p_set_check = settings_sub.add_parser("check-redeem", parents=[common], help="Check if Redeem Invite Code is in General Settings")
p_set_check.add_argument("node", choices=VALID_NODES, default="646", nargs="?", help="Target node (default: 646)")
# Domain: ONBOARD
p_onboard = subparsers.add_parser("onboard", parents=[common], help="Agent onboarding & automated invite code salvage pipeline")
onboard_sub = p_onboard.add_subparsers(dest="onboard_action")
p_onb_start = onboard_sub.add_parser("start", parents=[common], help="Start onboarding pipeline (provisions infra + initiates auth)")
p_onb_start.add_argument("node", help="Target new node label (e.g. dev2, client1)")
p_onb_start.add_argument("--email", required=True, help="Client login email")
p_onb_start.add_argument("--for", dest="for_agent", choices=VALID_NODES, help="Beneficiary agent to unblock (defaults to most urgent)")
p_onb_start.add_argument("--code", help="Explicit 6-character invite code to redeem")
p_onb_start.add_argument("--account-name", help="Display name hint for multi-account selection")
p_onb_otp = onboard_sub.add_parser("submit-otp", parents=[common], help="Submit transient OTP and complete auto-redemption")
p_onb_otp.add_argument("node", help="Target node label")
p_onb_otp.add_argument("otp", help="6-digit verification code")
p_onb_otp.add_argument("--email", help="Client email (optional)")
p_onb_stat = onboard_sub.add_parser("status", parents=[common], help="Query onboarding pipeline state for a node")
p_onb_stat.add_argument("node", help="Target node label")
p_onb_wo = onboard_sub.add_parser("salvage-wo", parents=[common], help="Dispatch cryptographically signed salvage work order to sidechat")
p_onb_wo.add_argument("node", nargs="?", default="646", choices=VALID_NODES, help="Blocked agent node (default: 646)")
p_onb_wo.add_argument("--target", default="646 tasks", help="Target sidechat (default: 646 tasks)")
onboard_sub.add_parser("feed-matrix", parents=[common], help="Display all agents ranked by feeding weight, job volume, role, and work done over time")
onboard_sub.add_parser("connects", parents=[common], help="Inventory of all active fleet nodes & client onboard connects")
# Domain: KPI
p_kpi = subparsers.add_parser("kpi", parents=[common], help="Fleet KPI, spend monitoring & runtime preservation")
p_kpi.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
kpi_sub = p_kpi.add_subparsers(dest="kpi_action")
p_kpi_status = kpi_sub.add_parser("status", parents=[common], help="Show fleet KPI dashboard (default)")
p_kpi_status.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_kpi_report = kpi_sub.add_parser("report", parents=[common], help="Detailed KPI & preservation report for an agent")
p_kpi_report.add_argument("node", choices=VALID_NODES, help="Target node")
p_kpi_routes = kpi_sub.add_parser("routes", parents=[common], help="Check route and CDP health across agents")
p_kpi_spawn = kpi_sub.add_parser("spawn-worker", parents=[common], help="Spawn background tmux worker to preserve runtime")
p_kpi_spawn.add_argument("node", choices=VALID_NODES, help="Target agent")
p_kpi_spawn.add_argument("session", help="Session label")
p_kpi_spawn.add_argument("worker_command", help="Command to run in background")
p_kpi_autospawn = kpi_sub.add_parser("auto-spawn", parents=[common], help="Reconcile idle agents and auto-spawn background tmux workers")
p_kpi_autospawn.add_argument("--node", choices=VALID_NODES, default=None, help="Filter by node")
p_kpi_autospawn.add_argument("--dry-run", action="store_true", help="Observe and report what would be spawned without executing")
# Domain: CHROMEBOX
p_chromebox = subparsers.add_parser("chromebox", parents=[common], help="Agent browser settings-menu toggles (chromebox RPA)")
chrome_sub = p_chromebox.add_subparsers(dest="chrome_action")
p_chrome_perm = chrome_sub.add_parser("permissions", parents=[common], help="Settings menu toggles (permissions + related tabs)")
p_chrome_perm.add_argument("node", choices=VALID_NODES, help="Target node")
perm_sub = p_chrome_perm.add_subparsers(dest="perm_action")
p_perm_list = perm_sub.add_parser("list", parents=[common], help="List toggle states (default)")
p_perm_list.add_argument("--tab", default=None, help="Only this settings tab")
p_perm_get = perm_sub.add_parser("get", parents=[common], help="Read one toggle")
p_perm_get.add_argument("toggle", help="Toggle address (e.g. permissions.web_access, permissions.websites:example.com)")
p_perm_set = perm_sub.add_parser("set", parents=[common], help="Set one toggle (verified with readback)")
p_perm_set.add_argument("toggle", help="Toggle address")
p_perm_set.add_argument("value", help="Value (on/off, Allow/Ask/Deny, auto_allow/always_ask, theme name)")
p_perm_desc = perm_sub.add_parser("describe", parents=[common], help="Full inventory of one settings tab (JSON)")
p_perm_desc.add_argument("tab", help="Settings tab name (e.g. Permissions)")
# Domain: DM
p_dm = subparsers.add_parser("dm", parents=[common], help="Inter-agent DMs, work orders ([WO]), acks, live log tail")
dm_sub = p_dm.add_subparsers(dest="action")
# super dm send
p_dm_send = dm_sub.add_parser("send", parents=[common], help="Send a direct message")
p_dm_send.add_argument("--to", required=True, choices=VALID_NODES, help="Recipient node")
p_dm_send.add_argument("--from", dest="from_agent", default=DEFAULT_SENDER, help="Sender identity (default: super)")
p_dm_send.add_argument("--target", default="main", help="Target chat/sidechat (default: main)")
p_dm_send.add_argument("--allow-main-chat", action="store_true", help="Explicit override allowing send directly to Main Chat")
p_dm_send.add_argument("-w", "--wait", action="store_true", help="Wait for recipient agent to reply")
p_dm_send.add_argument("-t", "--timeout", type=int, default=60, help="Wait timeout in seconds (default: 60)")
p_dm_send.add_argument("--expect-reply", action="store_true", help="Arm follow-up tracking")
p_dm_send.add_argument("--reply-timeout", type=int, default=None, help="Timeout in seconds")
p_dm_send.add_argument("--no-sign", action="store_true", help="Send without cryptographic SSH signature")
p_dm_send.add_argument("message", help="Message body")
# super dm chat
p_dm_chat = dm_sub.add_parser("chat", parents=[common], help="Interactive conversational chat session with an agent")
p_dm_chat.add_argument("agent", choices=VALID_NODES, help="Target agent to converse with")
p_dm_chat.add_argument("--target", default=None, help="Target sidechat or 'main'")
p_dm_chat.add_argument("-t", "--timeout", type=int, default=60, help="Reply timeout in seconds (default: 60)")
# super dm send-file
p_dm_sf = dm_sub.add_parser("send-file", parents=[common], help="Transfer a file to an agent and send a pointer in chat")
p_dm_sf.add_argument("--to", required=True, choices=VALID_NODES, help="Recipient node")
p_dm_sf.add_argument("--target", default=None, help="Target sidechat (default: agent primary task sidechat)")
p_dm_sf.add_argument("--note", default=None, help="Optional operator note or instructions")
p_dm_sf.add_argument("-w", "--wait", action="store_true", help="Wait for recipient agent to reply/acknowledge")
p_dm_sf.add_argument("-t", "--timeout", type=int, default=60, help="Reply timeout in seconds (default: 60)")
p_dm_sf.add_argument("file", help="Path to file to transfer")
# super dm files
p_dm_files = dm_sub.add_parser("files", parents=[common], help="List transferred files and staged payloads")
p_dm_files.add_argument("files_action", nargs="?", default="list", choices=["list", "clean"], help="Action: list (default) or clean")
p_dm_files.add_argument("--agent", choices=VALID_NODES, default=None, help="Filter by recipient agent")
p_dm_files.add_argument("--older-than", type=int, default=7, help="Retention cutoff in days for clean (default: 7)")
# super dm wo
p_dm_wo = dm_sub.add_parser("wo", parents=[common], help="Dispatch a structured Work Order ([WO:...])")
p_dm_wo.add_argument("--to", required=True, choices=VALID_NODES, help="Recipient node")
p_dm_wo.add_argument("--title", required=True, help="Work Order title")
p_dm_wo.add_argument("--priority", choices=["routine", "urgent"], default="routine", help="Priority level")
p_dm_wo.add_argument("--from", dest="from_agent", default=DEFAULT_SENDER, help="Sender identity (default: super)")
p_dm_wo.add_argument("--target", default=None, help="Target sidechat (default: agent primary task sidechat)")
p_dm_wo.add_argument("--allow-main-chat", action="store_true", help="Explicit override allowing work order in Main Chat")
p_dm_wo.add_argument("--no-wait", dest="wait", action="store_false", help="Do not wait for reply")
p_dm_wo.add_argument("-t", "--timeout", type=int, default=60, help="Wait timeout in seconds (default: 60)")
p_dm_wo.add_argument("--no-sign", action="store_true", help="Issue without cryptographic SSH signature")
p_dm_wo.add_argument("body", help="Work Order detailed description")
# super dm ack
p_dm_ack = dm_sub.add_parser("ack", parents=[common], help="Acknowledge a DM or Work Order")
p_dm_ack.add_argument("id", help="DM ID or Work Order ID")
p_dm_ack.add_argument("--to", required=True, choices=VALID_NODES, help="Recipient node")
p_dm_ack.add_argument("--from", dest="from_agent", default=DEFAULT_SENDER, help="Sender identity (default: super)")
p_dm_ack.add_argument("--target", default="main", help="Target chat (default: main)")
# super dm log
p_dm_log = dm_sub.add_parser("log", parents=[common], help="Display recent DM activity")
p_dm_log.add_argument("-n", type=int, default=25, help="Number of records to show")
p_dm_log.add_argument("--agent", choices=VALID_NODES, default=None, help="Filter by agent")
p_dm_log.add_argument("--filter", default=None, help="Search filter in text")
# super dm tail
p_dm_tail = dm_sub.add_parser("tail", parents=[common], help="Live stream incoming DMs")
p_dm_tail.add_argument("--filter", default=None, help="Search filter in text")
# super dm verify
p_dm_verify = dm_sub.add_parser("verify", parents=[common], help="Verify cryptographic signature on a DM")
p_dm_verify.add_argument("message", nargs="?", default=None, help="Message text containing signature block")
p_dm_verify.add_argument("--agent", choices=VALID_NODES, default=None, help="Scan agent's recent reads")
p_dm_verify.add_argument("--target", default=None, help="Scan target chat's recent reads")
# Domain: THREAD
p_thread = subparsers.add_parser("thread", parents=[common], help="Inspect agent main chats, sidechats, and scrollbacks")
thread_sub = p_thread.add_subparsers(dest="action")
p_thread_list = thread_sub.add_parser("list", parents=[common], help="List active threads for an agent or all fleet sidechats")
p_thread_list.add_argument("agent", nargs="?", default=None, choices=VALID_NODES + [None], help="Agent node to inspect (default: all registered fleet sidechats)")
p_thread_view = thread_sub.add_parser("view", parents=[common], help="View recent messages from an agent's thread")
p_thread_view.add_argument("agent", choices=VALID_NODES, help="Agent node to inspect")
p_thread_view.add_argument("thread_id", help="Thread UUID or 'main'")
p_thread_view.add_argument("--limit", type=int, default=15, help="Number of messages to retrieve")
# Domain: JOB
p_job = subparsers.add_parser("job", parents=[common], help="Manage scheduled jobs, systemd timers, triggers, logs")
job_sub = p_job.add_subparsers(dest="action")
p_job_list = job_sub.add_parser("list", parents=[common], help="List defined jobs")
p_job_list.add_argument("--archived", "-a", action="store_true", help="Include archived jobs from jobs/archive/")
p_job_show = job_sub.add_parser("show", parents=[common], help="Inspect full job definition and timer details")
p_job_show.add_argument("name", help="Job name")
p_job_status = job_sub.add_parser("status", parents=[common], help="Check timer status")
p_job_status.add_argument("name", nargs="?", default=None, help="Job/timer name")
p_job_create = job_sub.add_parser("create", parents=[common], help="Create or update a scheduled job")
p_job_create.add_argument("name", help="Job name (^[a-z0-9-]{1,64}$)")
p_job_create.add_argument("--agent", choices=VALID_NODES, default=None, help="Target agent")
p_job_create.add_argument("--schedule", default=None, help="Cron schedule (e.g. '*/15 * * * *' or 'manual')")
p_job_create.add_argument("--prompt", default=None, help="Prompt template")
p_job_create.add_argument("--description", default=None, help="Job description")
p_job_create.add_argument("--timeout", type=int, default=300, help="Timeout in seconds (60-3600, default: 300)")
p_job_create.add_argument("--on-failure", choices=["alert", "retry", "ignore"], default="alert", help="Failure policy")
p_job_create.add_argument("--chain-next", default=None, help="Next job name to chain on success")
p_job_create.add_argument("--sidechat-create", action="store_true", help="Dispatch in a sidechat")
p_job_create.add_argument("--sidechat-name", default=None, help="Sidechat name template")
p_job_create.add_argument("--reuse-key", default=None, help="Sidechat reuse key")
p_job_create.add_argument("--dm-target", default=None, help="Target chat or thread name")
p_job_create.add_argument("--file", default=None, help="Path to JSON file with job definition (or '-' for stdin)")
p_job_create.add_argument("--no-enable", action="store_true", help="Do not enable systemd timer immediately")
p_job_create.add_argument("--update", action="store_true", help="Allow updating an existing job")
p_job_enable = job_sub.add_parser("enable", parents=[common], help="Enable and activate a job's systemd timer")
p_job_enable.add_argument("name", help="Job name")
p_job_disable = job_sub.add_parser("disable", parents=[common], help="Stop and disable a job's systemd timer")
p_job_disable.add_argument("name", help="Job name")
p_job_delete = job_sub.add_parser("delete", parents=[common], help="Delete a job and its timer")
p_job_delete.add_argument("name", help="Job name")
p_job_delete.add_argument("-y", "--yes", action="store_true", help="Bypass confirmation prompt")
p_job_delete.add_argument("--force", action="store_true", help="Force deletion even if timer error")
p_job_run = job_sub.add_parser("run", parents=[common], help="Trigger a job immediately")
p_job_run.add_argument("name", help="Job name to trigger")
p_job_run.add_argument("-f", "--follow", action="store_true", help="Stream live dispatch and execution events")
p_job_log = job_sub.add_parser("log", parents=[common], help="View recent job execution events")
p_job_log.add_argument("-n", type=int, default=20, help="Number of events")
p_job_log.add_argument("name", nargs="?", default=None, help="Filter by job name")
p_job_archive = job_sub.add_parser("archive", parents=[common], help="Archive a retired manual job to jobs/archive/")
p_job_archive.add_argument("name", help="Job name to archive")
p_job_archive.add_argument("--force", action="store_true", help="Force archive even if marked protected")
p_job_unarchive = job_sub.add_parser("unarchive", parents=[common], help="Restore an archived job from jobs/archive/")
p_job_unarchive.add_argument("name", help="Job name to restore")
# Domain: WEB
p_web = subparsers.add_parser("web", parents=[common], help="Probe VM web surfaces (box.muse-dev.online), auth, sync")
web_sub = p_web.add_subparsers(dest="action")
web_sub.add_parser("health", parents=[common], help="Check Google Cloud VM web surface health")
web_sub.add_parser("test-auth", parents=[common], help="Verify operator auth gating on the VM")
web_sub.add_parser("sync", parents=[common], help="Check local log size and sync integrity")
# Domain: CRED
p_cred = subparsers.add_parser("cred", parents=[common], help="Credential console API & client onboarding")
cred_sub = p_cred.add_subparsers(dest="action")
p_c_init = cred_sub.add_parser("initiate", parents=[common], help="Initiate onboarding flow for a node")
p_c_init.add_argument("--node", required=True, help="Node label (e.g. opm, pip, 646)")
p_c_init.add_argument("--email", required=True, help="Client login email")
p_c_init.add_argument("--service", default="muse", help="Service name (default: muse)")
p_c_init.add_argument("--account-name", default=None, help="Display name hint for multi-account selector")
p_c_otp = cred_sub.add_parser("submit-otp", parents=[common], help="Submit transient OTP verification code")
p_c_otp.add_argument("--node", required=True, help="Node label")
p_c_otp.add_argument("--otp", required=True, help="6-digit verification code")
p_c_otp.add_argument("--email", default=None, help="Client email (optional)")
p_c_stat = cred_sub.add_parser("status", parents=[common], help="Query onboarding & vitality status for a node")
p_c_stat.add_argument("--node", required=True, help="Node label")
p_c_link = cred_sub.add_parser("link-instagram", parents=[common], help="Generate Tailscale one-tap portal & OAuth link for age verification")
p_c_link.add_argument("--node", required=True, help="Node label")
p_c_link.add_argument("--notify", action="store_true", help="Send email alert to operator via local MTA")
p_c_audit = cred_sub.add_parser("meta-audit", parents=[common], help="Audit Meta Accounts Center for linked profiles and email")
p_c_audit.add_argument("--node", required=True, help="Node label")
cred_sub.add_parser("list", parents=[common], help="List all registered nodes and vitality statuses")
# Domain: SSH
p_ssh = subparsers.add_parser("ssh", parents=[common], help="Mint and manage fleet SSH signing/access keys")
ssh_sub = p_ssh.add_subparsers(dest="action")
p_s_mint = ssh_sub.add_parser("mint", parents=[common], help="Mint a new ed25519 SSH keypair and register in allowed_signers")
p_s_mint.add_argument("name", help="Identity/agent name (e.g. 646, pip, dev, canary)")
p_s_mint.add_argument("--force", action="store_true", help="Overwrite existing keypair")
p_s_list = ssh_sub.add_parser("list", parents=[common], help="List managed SSH keypairs and registration status")
p_s_show = ssh_sub.add_parser("show", parents=[common], help="Show public key content and fingerprint")
p_s_show.add_argument("name", help="Identity/agent name")
p_s_ports = ssh_sub.add_parser("ports", parents=[common], help="List container reverse tunnel port mappings")
p_s_info = ssh_sub.add_parser("info", parents=[common], help="Show SSH dial-in commands and reverse tunnel coordinates")
p_s_info.add_argument("name", help="Agent identity (e.g. 646, muse, pip)")
p_s_check = ssh_sub.add_parser("check", parents=[common], help="Live SSH/terminal tunnel health sweep via jump host")
# Domain: MD (Hatch Agent Markdown & Operational Drive)
p_md = subparsers.add_parser("md", parents=[common], help="Manage agent .md system files & inject operational DRIVE via Hatch")
md_sub = p_md.add_subparsers(dest="action")
p_md_audit = md_sub.add_parser("audit", parents=[common], help="Audit .md files and DRIVE scores across fleet agents")
p_md_audit.add_argument("accounts", nargs="*", help="Optional account filter")
p_md_list = md_sub.add_parser("list", parents=[common], help="List files in agent container via Hatch")
p_md_list.add_argument("account", help="Agent account (e.g. muse, pip, 646, opm, def, dev)")
p_md_list.add_argument("path", nargs="?", default="", help="Subdirectory path")
p_md_read = md_sub.add_parser("read", parents=[common], help="Read an agent .md file via Hatch")
p_md_read.add_argument("account", help="Agent account")
p_md_read.add_argument("filename", help="Filename (e.g. SOUL.md, HEARTBEAT.md)")
p_md_write = md_sub.add_parser("write", parents=[common], help="Write an agent .md file via Hatch")
p_md_write.add_argument("account", help="Agent account")
p_md_write.add_argument("filename", help="Filename (e.g. SOUL.md)")
p_md_write.add_argument("--content", help="Text content to write")
p_md_write.add_argument("--file", help="Local file to copy from")
p_md_diff = md_sub.add_parser("diff", parents=[common], help="Diff container .md file against shared operator template")
p_md_diff.add_argument("account", help="Agent account")
p_md_diff.add_argument("filename", help="Filename (e.g. SOUL.md)")
p_md_drive = md_sub.add_parser("inject-drive", parents=[common], help="Inject high-drive operator files into an agent container")
p_md_drive.add_argument("account", help="Agent account")
p_md_drive.add_argument("--force", action="store_true", help="Force overwrite")
p_md_sync = md_sub.add_parser("sync-all", parents=[common], help="Inject high-drive operator files across all active fleet agents")
p_md_sync.add_argument("--force", action="store_true", help="Force overwrite")
p_md_amend = md_sub.add_parser("amend", parents=[common], help="Amend centralized shared operator file with validation and git commit")
p_md_amend.add_argument("filename", help="Filename (e.g. AGENTS.md, TOOLS.md)")
p_md_amend.add_argument("--content", help="New content")
p_md_amend.add_argument("--file", help="File with new content")
p_md_amend.add_argument("--author", default="operator", help="Author of amendment")
p_md_amend.add_argument("--reason", default="", help="Reason for amendment")
p_md_append = md_sub.add_parser("append", parents=[common], help="Safely append a lesson or note to a shared operator file")
p_md_append.add_argument("filename", help="Filename (e.g. AGENTS.md)")
p_md_append.add_argument("text", help="Text to append")
p_md_append.add_argument("--author", default="operator", help="Author of amendment")
p_md_append.add_argument("--section", default=None, help="Optional section header")
p_md_pull = md_sub.add_parser("pull", parents=[common], help="Pull canonical shared template into an agent container")
p_md_pull.add_argument("account", help="Agent account")
p_md_pull.add_argument("filename", help="Filename (e.g. SOUL.md)")
p_md_wd = md_sub.add_parser("watchdog", parents=[common], help="Fleet agent drive watchdog daemon & status")
p_md_wd.add_argument("sub_action", choices=["status", "run"], nargs="?", default="status", help="Watchdog action: status (default) or run (execute cycle)")
p_md_wd.add_argument("--no-heal", action="store_true", help="Audit only; do not auto-heal degraded agents")
# Domain: HARVEST
p_harvest = subparsers.add_parser("harvest", parents=[common], help="Readback & response harvesting engine")
harvest_sub = p_harvest.add_subparsers(dest="action")
p_h_run = harvest_sub.add_parser("run", parents=[common], help="Run a harvest cycle immediately")
p_h_run.add_argument("--agent", choices=VALID_NODES, default=None, help="Target specific agent")
p_h_run.add_argument("--dry-run", action="store_true", help="Scrape without persisting watermarks")
p_h_status = harvest_sub.add_parser("status", parents=[common], help="Display active watermarks and harvest metrics")
p_h_tail = harvest_sub.add_parser("tail", parents=[common], help="Live stream ingested chat messages")
p_h_tail.add_argument("--filter", default=None, help="Search filter in text")
# Domain: FOLLOWUP
p_followup = subparsers.add_parser("followup", parents=[common], help="Scheduled follow-up deadline tracking and nudges")
followup_sub = p_followup.add_subparsers(dest="action")
p_f_list = followup_sub.add_parser("list", parents=[common], help="List tracked follow-ups and deadlines")
p_f_list.add_argument("--all", action="store_true", help="Include resolved and historical records")
p_f_sweep = followup_sub.add_parser("sweep", parents=[common], help="Trigger deadline check and nudge dispatch immediately")
p_f_sweep.add_argument("--dry-run", action="store_true", help="Simulate sweep without sending DMs")
p_f_cancel = followup_sub.add_parser("cancel", parents=[common], help="Cancel a pending follow-up")
p_f_cancel.add_argument("dm_id", help="DM ID to cancel")
# Domain: LOOP (Intrinsic Loop Management)
p_loop = subparsers.add_parser("loop", parents=[common], help="Intrinsic loop strategy, health, break taxonomy, and variables")
loop_sub = p_loop.add_subparsers(dest="action")
p_l_status = loop_sub.add_parser("status", parents=[common], help="Show active and recent intrinsic loops")
p_l_status.add_argument("--agent", choices=VALID_NODES, default=None, help="Filter by agent")
p_l_status.add_argument("--status", choices=["pending", "active", "nudged", "escalated", "closed", "resolved", "all"], default=None, help="Filter by state")
p_l_status.add_argument("-n", type=int, default=30, help="Number of loops to display")
p_l_health = loop_sub.add_parser("health", parents=[common], help="Evaluate per-agent and fleet loop health metrics")
p_l_health.add_argument("--threshold", type=float, default=None, help="Health ratio threshold (default: 0.5)")
p_l_breaks = loop_sub.add_parser("breaks", parents=[common], help="Run break detection diagnostics across loops")
# loop strat
p_l_strat = loop_sub.add_parser("strat", parents=[common], help="Inspect and configure loop modulation strategies")
strat_sub = p_l_strat.add_subparsers(dest="strat_action")
p_ls_show = strat_sub.add_parser("show", parents=[common], help="Display active modulation strategy matrix")
p_ls_show.add_argument("type", nargs="?", default=None, help="Filter by input type (wake, job, siphon, manual, health, heartbeat)")
p_ls_set = strat_sub.add_parser("set", parents=[common], help="Override loop modulation strategy")
p_ls_set.add_argument("type", help="Input type (wake, job, siphon, manual, health, heartbeat)")
p_ls_set.add_argument("--subtype", default=None, help="Subtype (e.g. overdue, canary, alert, blocker)")
p_ls_set.add_argument("--agent", choices=VALID_NODES, default=None, help="Target agent scope")
p_ls_set.add_argument("--track", choices=["true", "false", "actionable", "always", "never"], default=None, help="Track mode")
p_ls_set.add_argument("--priority", choices=["routine", "normal", "important", "critical"], default=None, help="Priority rank")
p_ls_set.add_argument("--timeout", type=int, default=None, help="Timeout in seconds before nudge")
p_ls_set.add_argument("--nudges", type=int, default=None, help="Max automatic nudges")
p_ls_set.add_argument("--escalate", default=None, help="Escalation target identity (e.g. opm, user, none)")
p_ls_reset = strat_sub.add_parser("reset", parents=[common], help="Reset loop strategy override to builtin default")
p_ls_reset.add_argument("type", help="Input type")
p_ls_reset.add_argument("--subtype", default=None, help="Subtype")
p_ls_reset.add_argument("--agent", choices=VALID_NODES, default=None, help="Target agent scope")
p_ls_eval = strat_sub.add_parser("eval", parents=[common], help="Evaluate/simulate strategy resolution for input")
p_ls_eval.add_argument("type", help="Input type")
p_ls_eval.add_argument("--subtype", default=None, help="Subtype")
p_ls_eval.add_argument("--agent", choices=VALID_NODES, default=None, help="Target agent scope")
p_ls_eval.add_argument("--actionable", action="store_true", help="Actionable flag (for wake)")
# loop vars
p_l_vars = loop_sub.add_parser("vars", parents=[common], help="Inspect and adjust runtime control variables")
vars_sub = p_l_vars.add_subparsers(dest="vars_action")
vars_sub.add_parser("list", parents=[common], help="List all registered control variables")
p_lv_get = vars_sub.add_parser("get", parents=[common], help="Inspect a specific control variable")
p_lv_get.add_argument("name", help="Variable name")
p_lv_set = vars_sub.add_parser("set", parents=[common], help="Set a control variable value")
p_lv_set.add_argument("name", help="Variable name")
p_lv_set.add_argument("value", help="New value")
p_lv_reset = vars_sub.add_parser("reset", parents=[common], help="Reset a control variable to default")
p_lv_reset.add_argument("name", help="Variable name")
p_lv_hist = vars_sub.add_parser("history", parents=[common], help="Show variable modification audit history")
p_lv_hist.add_argument("name", nargs="?", default=None, help="Variable name")
p_lv_hist.add_argument("-n", "--limit", type=int, default=20, help="Number of records")
p_lv_rb = vars_sub.add_parser("rollback", parents=[common], help="Roll back a variable to a previous value")
p_lv_rb.add_argument("name", help="Variable name")
p_lv_rb.add_argument("--revision", default=None, help="Revision step (int) or timestamp")
p_l_remed = loop_sub.add_parser("remediate", parents=[common], help="Run progressive auto-remediation for soft breaks")
p_l_remed.add_argument("--dry-run", action="store_true", help="Simulate remediation without applying fixes")
p_l_close = loop_sub.add_parser("close", parents=[common], help="Manually close/resolve a pending loop")
p_l_close.add_argument("dm_id", help="DM ID or Loop ID")
p_l_close.add_argument("--note", default=None, help="Resolution note")
p_l_nudge = loop_sub.add_parser("nudge", parents=[common], help="Trigger immediate nudge for a pending loop")
p_l_nudge.add_argument("dm_id", help="DM ID or Loop ID")
p_l_sweep = loop_sub.add_parser("sweep", parents=[common], help="Run immediate sweep cycle")
p_l_sweep.add_argument("--dry-run", action="store_true", help="Simulate sweep without sending DMs")
p_l_harvest = loop_sub.add_parser("harvest", parents=[common], help="Run immediate harvest cycle")
p_l_harvest.add_argument("--dry-run", action="store_true", help="Scrape without persisting watermarks")
# Domain: PIPELINE
p_pipe = subparsers.add_parser("pipeline", parents=[common], help="Multi-agent workflow pipelines and chained handoffs")
pipe_sub = p_pipe.add_subparsers(dest="action")
p_pipe_run = pipe_sub.add_parser("run", parents=[common], help="Start a new multi-agent pipeline run")
p_pipe_run.add_argument("name", help="Root pipeline job name (e.g. pipe-demo-step1)")
p_pipe_run.add_argument("--dry-run", action="store_true", help="Simulate pipeline without sending DMs")
p_pipe_status = pipe_sub.add_parser("status", parents=[common], help="Display active pipeline runs and step states")
p_pipe_hist = pipe_sub.add_parser("history", parents=[common], help="Show historical pipeline runs and outcomes")
p_pipe_hist.add_argument("-n", "--limit", type=int, default=20, help="Number of records to display")
p_pipe_stop = pipe_sub.add_parser("stop", parents=[common], help="Cancel/stop an active pipeline run")
p_pipe_stop.add_argument("run_id", help="Pipeline run ID (prefix match supported)")
p_pipe_stop.add_argument("--reason", default="cancelled_by_operator", help="Cancellation reason")
p_pipe_prune = pipe_sub.add_parser("prune", parents=[common], help="Prune/timeout stale running pipelines")
p_pipe_prune.add_argument("--max-age", type=float, default=1.0, help="Max age in hours (default 1.0)")
# Top-level domain aliases: strat and vars
p_strat_alias = subparsers.add_parser("strat", parents=[common], help="Shortcut for 'loop strat'")
strat_alias_sub = p_strat_alias.add_subparsers(dest="strat_action")
p_sa_show = strat_alias_sub.add_parser("show", parents=[common], help="Display active modulation strategy matrix")
p_sa_show.add_argument("type", nargs="?", default=None, help="Filter by input type")
p_sa_set = strat_alias_sub.add_parser("set", parents=[common], help="Override loop modulation strategy")
p_sa_set.add_argument("type", help="Input type")
p_sa_set.add_argument("--subtype", default=None, help="Subtype")
p_sa_set.add_argument("--agent", choices=VALID_NODES, default=None, help="Target agent scope")
p_sa_set.add_argument("--track", choices=["true", "false", "actionable", "always", "never"], default=None, help="Track mode")
p_sa_set.add_argument("--priority", choices=["routine", "normal", "important", "critical"], default=None, help="Priority rank")
p_sa_set.add_argument("--timeout", type=int, default=None, help="Timeout in seconds before nudge")
p_sa_set.add_argument("--nudges", type=int, default=None, help="Max automatic nudges")
p_sa_set.add_argument("--escalate", default=None, help="Escalation target identity")
p_sa_reset = strat_alias_sub.add_parser("reset", parents=[common], help="Reset loop strategy override")
p_sa_reset.add_argument("type", help="Input type")
p_sa_reset.add_argument("--subtype", default=None, help="Subtype")
p_sa_reset.add_argument("--agent", choices=VALID_NODES, default=None, help="Target agent scope")
p_sa_eval = strat_alias_sub.add_parser("eval", parents=[common], help="Evaluate/simulate strategy resolution")
p_sa_eval.add_argument("type", help="Input type")
p_sa_eval.add_argument("--subtype", default=None, help="Subtype")
p_sa_eval.add_argument("--agent", choices=VALID_NODES, default=None, help="Target agent scope")
p_sa_eval.add_argument("--actionable", action="store_true", help="Actionable flag")
p_vars_alias = subparsers.add_parser("vars", parents=[common], help="Shortcut for 'loop vars'")
vars_alias_sub = p_vars_alias.add_subparsers(dest="vars_action")
vars_alias_sub.add_parser("list", parents=[common], help="List all control variables")
p_va_get = vars_alias_sub.add_parser("get", parents=[common], help="Inspect a specific control variable")
p_va_get.add_argument("name", help="Variable name")
p_va_set = vars_alias_sub.add_parser("set", parents=[common], help="Set a control variable value")
p_va_set.add_argument("name", help="Variable name")
p_va_set.add_argument("value", help="New value")
p_va_reset = vars_alias_sub.add_parser("reset", parents=[common], help="Reset a control variable to default")
p_va_reset.add_argument("name", help="Variable name")
p_va_hist = vars_alias_sub.add_parser("history", parents=[common], help="Show variable modification audit history")
p_va_hist.add_argument("name", nargs="?", default=None, help="Variable name")
p_va_hist.add_argument("-n", "--limit", type=int, default=20, help="Number of records")
p_va_rb = vars_alias_sub.add_parser("rollback", parents=[common], help="Roll back a variable to a previous value")
p_va_rb.add_argument("name", help="Variable name")
p_va_rb.add_argument("--revision", default=None, help="Revision step (int) or timestamp")
# Domain: deploy (Deploy multi-agent pipelines or subagent tasks with oversight)
p_deploy = subparsers.add_parser("deploy", parents=[common], help="Deploy multi-agent task or pipeline across nodes with live oversight")
deploy_sub = p_deploy.add_subparsers(dest="action")
p_dep_pipe = deploy_sub.add_parser("pipeline", parents=[common], help="Deploy multi-agent pipeline")
p_dep_pipe.add_argument("name", help="Pipeline root job name (e.g. pipe-demo-step1)")
p_dep_pipe.add_argument("--dry-run", action="store_true", help="Simulate pipeline without sending DMs")
p_dep_sub = deploy_sub.add_parser("subagent", parents=[common], help="Spawn sub-agent session and dispatch task")
p_dep_sub.add_argument("--agent", required=True, choices=VALID_NODES, help="Agent node to spawn subagent on")
p_dep_sub.add_argument("--title", default="subagent-task", help="Title for the subagent session")
p_dep_sub.add_argument("prompt", help="Task prompt for the subagent")
p_dep_sub.add_argument("--wait", type=int, default=30, help="Seconds to wait for subagent response")
# Domain: SWARM
p_swarm = subparsers.add_parser("swarm", parents=[common], help="Manage multi-agent swarm tasks and worker allocations")
swarm_sub = p_swarm.add_subparsers(dest="action")
p_sw_list = swarm_sub.add_parser("list", parents=[common], help="List all swarms and slot rollups")
p_sw_status = swarm_sub.add_parser("status", parents=[common], help="Show status and slot details for a swarm")
p_sw_status.add_argument("swarm_id", help="Swarm identifier (sw-...)")
p_sw_spawn = swarm_sub.add_parser("spawn", parents=[common], help="Spawn a new multi-slot worker swarm")
p_sw_spawn.add_argument("count", type=int, help="Number of worker slots (1-50)")
p_sw_spawn.add_argument("task", help="Task prompt for the swarm workers")
p_sw_spawn.add_argument("--label", default=None, help="Optional tracking label")
p_sw_prune = swarm_sub.add_parser("prune", parents=[common], help="Archive stale partial/terminal swarms")
p_sw_prune.add_argument("--stale-hours", type=float, default=6.0, help="Hours of inactivity before pruning (default: 6)")
p_sw_prune.add_argument("--confirm", action="store_true", help="Confirm execution of pruning")
# Domain: subagent (Direct alias for spawning & managing subagents)
p_subagent = subparsers.add_parser("subagent", parents=[common], help="Spawn sub-agent session and dispatch task")
subagent_sub = p_subagent.add_subparsers(dest="action")
p_sub_spawn = subagent_sub.add_parser("spawn", parents=[common], help="Spawn sub-agent session and dispatch task")
p_sub_spawn.add_argument("--agent", required=True, choices=VALID_NODES, help="Agent node to spawn subagent on")
p_sub_spawn.add_argument("--title", default="subagent-task", help="Title for the subagent session")
p_sub_spawn.add_argument("prompt", help="Task prompt for the subagent")
p_sub_spawn.add_argument("--wait", type=int, default=30, help="Seconds to wait for subagent response")
# Domain: FLOW (Agentic workflows in persistent tmux panes with delta read-backs)
p_flow = subparsers.add_parser("flow", parents=[common], help="Manage agentic flows in persistent tmux panes (start, read, send, list, stop)")
p_flow.add_argument("flow_args", nargs=argparse.REMAINDER, help="Arguments passed directly to flow_engine.py")
# Domain: TMUX (Headless background tmux sessions with automatic logging)
p_tmux = subparsers.add_parser("tmux", parents=[common], help="Manage headless background tmux sessions on /tmp/tmux-muse.sock")
p_tmux.add_argument("tmux_args", nargs=argparse.REMAINDER, help="Arguments passed directly to muse-tmux.py")
# Domain: muse (fast headless gateway via muse-cli-node with isolated per-node Cloudflare WARP egress)
p_muse = subparsers.add_parser("muse", parents=[common], help="Direct headless gateway client (muse-cli-node)")
p_muse.add_argument("muse_args", nargs=argparse.REMAINDER, help="Arguments passed to muse-cli-node or fleet lookups")
# Domain: LOOKUP (Unified seamless lookups across nodes, threads, unread, approvals, key, docs)
p_lookup = subparsers.add_parser("lookup", aliases=["lookups"], parents=[common], help="Seamless fleet lookups (summary, fleet, threads, unread, approvals, key, docs)")
p_lookup.add_argument("target", nargs="?", default="summary", choices=["summary", "fleet", "nodes", "threads", "sidechats", "unread", "unreads", "approvals", "key", "passkey", "docs", "doc", "surfaces", "sentence", "regex", "parse"], help="Lookup target")
p_lookup.add_argument("lookup_args", nargs=argparse.REMAINDER, help="Additional arguments passed to lookup engine")
# Domain: PASSKEY (Operator passkey location & agent approval protocol)
p_passkey = subparsers.add_parser("passkey", aliases=["key"], parents=[common], help="Display operator passkey location (VM-only), PIN, & agent approval protocol")
p_passkey.add_argument("action", nargs="?", default="show", choices=["show", "fetch", "get"], help="Passkey action: 'show' details or 'fetch' from VM")
# Domain: DOCS (Internal agent lookups, surfaces, sentence grammar, and regex engine)
p_docs = subparsers.add_parser("docs", aliases=["doc"], parents=[common], help="Agent lookups, surfaces for box.muse-dev.online, sentence grammar & regex")
p_docs.add_argument("docs_args", nargs=argparse.REMAINDER, help="Arguments passed directly to docs-lookup.py")
# Domain: TUI (Interactive full-screen Muse TUI & Box fleet console)
p_tui = subparsers.add_parser("tui", parents=[common], help="Interactive full-screen Muse TUI & Box fleet console")
p_tui.add_argument("tui_args", nargs=argparse.REMAINDER, help="Arguments passed directly to muse-tui.py")
# Domain: SYSOP (one-shot fleet installer: link units, enable timers, anchor + verify)
p_sysop = subparsers.add_parser("sysop", parents=[common], help="Fleet operations: one-shot systemd unit installer")
sysop_sub = p_sysop.add_subparsers(dest="sysop_action")
p_sysop_install = sysop_sub.add_parser("install", parents=[common], help="Link systemd units, enable timers, anchor and verify them")
p_sysop_install.add_argument("--dry-run", action="store_true", help="Print actions without changing anything")
return parser
def main():
if len(sys.argv) > 1:
if sys.argv[1] == "tui":
tui_args = sys.argv[2:]
if tui_args and tui_args[0] in ("onboard", "tmux", "connects", "approvals"):
cmd = [sys.executable, str(BIN_DIR / "box-onboard-tui.py")] + tui_args[1:]
elif tui_args and tui_args[0] in ("fleet", "oversight"):
cmd = [sys.executable, str(BIN_DIR / "box-fleet-tui.py")] + tui_args[1:]
else:
cmd = [sys.executable, str(BIN_DIR / "muse-tui.py"), "--mode", "box"] + tui_args
res = subprocess.run(cmd)
sys.exit(res.returncode)
elif sys.argv[1] in ("onboard-tui", "dev-tui"):
cmd = [sys.executable, str(BIN_DIR / "box-onboard-tui.py")] + sys.argv[2:]
res = subprocess.run(cmd)
sys.exit(res.returncode)
elif sys.argv[1] in ("fleet-tui",):
cmd = [sys.executable, str(BIN_DIR / "box-fleet-tui.py")] + sys.argv[2:]
res = subprocess.run(cmd)
sys.exit(res.returncode)
elif sys.argv[1] == "tmux":
if len(sys.argv) > 2 and sys.argv[2] in ("tally", "auto", "watch", "once", "match", "rules", "status"):
if sys.argv[2] == "auto":
t_sub = sys.argv[3:] or ["status"]
else:
t_sub = sys.argv[2:]
cmd = [sys.executable, str(BIN_DIR / "tmux_auto_approver.py")] + t_sub
res = subprocess.run(cmd)
sys.exit(res.returncode)
cmd = [sys.executable, str(BIN_DIR / "muse-tmux.py")] + (sys.argv[2:] or ["list"])
res = subprocess.run(cmd)
sys.exit(res.returncode)
elif sys.argv[1] in ("tmux-auto", "auto-dev"):
cmd = [sys.executable, str(BIN_DIR / "tmux_auto_approver.py")] + sys.argv[2:]
res = subprocess.run(cmd)
sys.exit(res.returncode)
elif sys.argv[1] in ("docs", "doc"):
cmd = [sys.executable, str(BIN_DIR / "docs-lookup.py")] + sys.argv[2:]
res = subprocess.run(cmd)
sys.exit(res.returncode)
elif sys.argv[1] in ("stability", "stable"):
cmd = [sys.executable, str(NETVM_ROOT / "watchers" / "box-stability-watcher.py")]
sub = sys.argv[2:]
if not sub or sub[0] == "status":
cmd.append("--status")
elif sub[0] == "check":
cmd.append("--check")
elif sub[0] == "json":
cmd.extend(["--status", "--json"])
elif sub[0] == "resume" and len(sub) > 1:
cmd.extend(["--resume", sub[1]])
else:
cmd.extend(sub)
res = subprocess.run(cmd)
sys.exit(res.returncode)
elif sys.argv[1] == "muse":
m_args = sys.argv[2:]
if not m_args:
cmd = [str(BIN_DIR / "muse"), "--help"]
res = subprocess.run(cmd)
sys.exit(res.returncode)
if m_args[0] == "tmux":
cmd = [sys.executable, str(BIN_DIR / "muse-tmux.py")] + (m_args[1:] or ["list"])
res = subprocess.run(cmd)
sys.exit(res.returncode)
if m_args[0] in ("status", "fleet"):
sys.argv = [sys.argv[0], "fleet", "status"]
elif m_args[0] in ("passkey", "key"):
sys.argv = [sys.argv[0], "passkey"] + m_args[1:]
elif m_args[0] in ("lookup", "lookups"):
sys.argv = [sys.argv[0], "lookup"] + m_args[1:]
elif m_args[0] in ("threads", "sidechats"):
sys.argv = [sys.argv[0], "thread", "list"] + m_args[1:]
elif m_args[0] in ("unread", "unreads"):
sys.argv = [sys.argv[0], "lookup", "unread"]
elif m_args[0] in VALID_NODES:
node = m_args[0]
sub = m_args[1:]
if not sub:
sub = ["status"]
if sub[0] == "chat":
cmd = [sys.executable, str(BIN_DIR / "muse-chat-repl.py"), node] + sub[1:]
res = subprocess.run(cmd)
sys.exit(res.returncode)
cmd = [str(BIN_DIR / "muse-cli-node"), node] + sub
res = subprocess.run(cmd)
sys.exit(res.returncode)
else:
cmd = [str(BIN_DIR / "muse")] + m_args
res = subprocess.run(cmd)
sys.exit(res.returncode)
parser = build_parser()
if len(sys.argv) == 1:
# Default behavior with no arguments: show fleet status
sys.argv.append("fleet")
sys.argv.append("status")
args = parser.parse_args()
# Route commands
if args.domain == "fleet":
act = getattr(args, "action", "status") or "status"
if act == "status":
cmd_fleet_status(args)
elif act == "watch":
cmd_fleet_watch(args)
elif act == "restart":
if not getattr(args, "node", None):
print("Error: Specify node to restart (e.g. super fleet restart muse)", file=sys.stderr)
sys.exit(1)
cmd_fleet_restart(args)
elif act == "cdp":
if not getattr(args, "node", None):
print("Error: Specify node (e.g. super fleet cdp muse)", file=sys.stderr)
sys.exit(1)
cmd_fleet_cdp(args)
elif act == "heal":
if not getattr(args, "node", None):
print("Error: Specify node to heal (e.g. super fleet heal dev)", file=sys.stderr)
sys.exit(1)
cmd_fleet_heal(args)
elif args.domain == "watchdog":
act = getattr(args, "action", "status") or "status"
if act == "status":
cmd_watchdog_status(args)
elif act == "run":
if not getattr(args, "target", None):
print("Error: Specify node or 'relay' (e.g. box watchdog run dev)", file=sys.stderr)
sys.exit(1)
cmd_watchdog_run(args)
elif args.domain == "dm":
act = getattr(args, "action", None)
if not act or act == "log":
cmd_dm_log(args)
elif act == "send":
cmd_dm_send(args)
elif act == "wo":
cmd_dm_wo(args)
elif act == "ack":
cmd_dm_ack(args)
elif act == "tail":
cmd_dm_tail(args)
elif act == "chat":
cmd_dm_chat(args)
elif act == "send-file":
cmd_dm_send_file(args)
elif act == "files":
cmd_dm_files(args)
elif act == "verify":
cmd_dm_verify(args)
else:
parser.print_help()
elif args.domain == "thread":
act = getattr(args, "action", None)
if act == "list":
cmd_thread_list(args)
elif act == "view":
cmd_thread_view(args)
else:
parser.print_help()
elif args.domain == "job":
act = getattr(args, "action", None)
if not act or act == "list":
cmd_job_list(args)
elif act == "show":
cmd_job_show(args)
elif act == "create":
cmd_job_create(args)
elif act == "enable":
cmd_job_enable(args)
elif act == "disable":
cmd_job_disable(args)
elif act == "delete":
cmd_job_delete(args)
elif act == "status":
cmd_job_status(args)
elif act == "run":
cmd_job_run(args)
elif act == "log":
cmd_job_log(args)
elif act == "archive":
cmd_job_archive(args)
elif act == "unarchive":
cmd_job_unarchive(args)
else:
parser.print_help()
elif args.domain == "web":
act = getattr(args, "action", None)
if not act or act == "health":
cmd_web_health(args)
elif act == "test-auth":
cmd_web_test_auth(args)
elif act == "sync":
cmd_web_sync(args)
else:
parser.print_help()
elif args.domain == "cred":
act = getattr(args, "action", None)
if not act or act == "list":
cmd_cred_list(args)
elif act == "initiate":
cmd_cred_initiate(args)
elif act == "submit-otp":
cmd_cred_submit_otp(args)
elif act == "status":
cmd_cred_status(args)
elif act == "link-instagram":
cmd_cred_link_instagram(args)
elif act == "meta-audit":
cmd_cred_meta_audit(args)
else:
parser.print_help()
elif args.domain == "ssh":
act = getattr(args, "action", None)
if not act or act == "list":
cmd_ssh_list(args)
elif act == "mint":
cmd_ssh_mint(args)
elif act == "show":
cmd_ssh_show(args)
elif act == "ports":
cmd_ssh_ports(args)
elif act == "info":
cmd_ssh_info(args)
elif act == "check":
cmd_ssh_check(args)
else:
p_ssh.print_help()
elif args.domain == "md":
act = getattr(args, "action", None)
if not act or act == "audit":
cmd_md_audit(args)
elif act == "list":
cmd_md_list(args)
elif act == "read":
cmd_md_read(args)
elif act == "write":
cmd_md_write(args)
elif act == "diff":
cmd_md_diff(args)
elif act == "inject-drive":
cmd_md_inject_drive(args)
elif act == "sync-all":
cmd_md_sync_all(args)
elif act == "amend":
cmd_md_amend(args)
elif act == "append":
cmd_md_append(args)
elif act == "pull":
cmd_md_pull(args)
elif act == "watchdog":
cmd_md_watchdog(args)
else:
p_md.print_help()
elif args.domain == "harvest":
act = getattr(args, "action", None)
if not act or act == "status":
cmd_harvest_status(args)
elif act == "run":
cmd_harvest_run(args)
elif act == "tail":
cmd_harvest_tail(args)
else:
parser.print_help()
elif args.domain == "followup":
act = getattr(args, "action", None)
if not act or act == "list":
cmd_followup_list(args)
elif act == "sweep":
cmd_followup_sweep(args)
elif act == "cancel":
cmd_followup_cancel(args)
else:
parser.print_help()
elif args.domain == "pipeline":
act = getattr(args, "action", None)
if not act or act == "status":
cmd_pipeline_status(args)
elif act == "run":
cmd_pipeline_run(args)
elif act == "history":
cmd_pipeline_history(args)
elif act == "stop":
cmd_pipeline_stop(args)
elif act == "prune":
cmd_pipeline_prune(args)
else:
parser.print_help()
elif args.domain == "loop":
act = getattr(args, "action", None)
if not act or act == "status":
cmd_loop_status(args)
elif act == "health":
cmd_loop_health(args)
elif act == "breaks":
cmd_loop_breaks(args)
elif act == "strat":
cmd_loop_strat(args)
elif act == "vars":
cmd_loop_vars(args)
elif act == "close":
cmd_loop_close(args)
elif act == "nudge":
cmd_loop_nudge(args)
elif act == "sweep":
cmd_loop_sweep(args)
elif act == "harvest":
cmd_loop_harvest(args)
elif act == "remediate":
cmd_loop_remediate(args)
else:
parser.print_help()
elif args.domain == "strat":
cmd_loop_strat(args)
elif args.domain == "vars":
cmd_loop_vars(args)
elif args.domain == "swarm":
act = getattr(args, "action", None)
if not act or act == "list":
cmd_swarm_list(args)
elif act == "status":
cmd_swarm_status(args)
elif act == "spawn":
cmd_swarm_spawn(args)
elif act == "prune":
cmd_swarm_prune(args)
else:
p_swarm.print_help()
elif args.domain in ("approvals", "approval", "blocked"):
cmd_approvals(args)
elif args.domain == "muse-choices":
cmd_muse_choices(args)
elif args.domain == "runtime":
cmd_runtime(args)
elif args.domain == "work":
cmd_work(args)
elif args.domain == "tasks":
cmd_tasks(args)
elif args.domain == "invite":
cmd_invite(args)
elif args.domain == "usage":
cmd_usage(args)
elif args.domain == "settings":
cmd_settings(args)
elif args.domain == "onboard":
cmd_onboard(args)
elif args.domain == "kpi":
cmd_kpi(args)
elif args.domain == "chromebox":
cmd_chromebox(args)
elif args.domain in ("deploy", "subagent"):
if args.domain == "subagent":
args.action = "subagent"
cmd_deploy(args)
elif args.domain in ("lookup", "lookups"):
cmd_lookup(args)
elif args.domain in ("passkey", "key"):
cmd_passkey_info(args)
elif args.domain == "flow":
cmd_flow_dispatch(args)
elif args.domain == "tmux":
cmd_tmux_dispatch(args)
elif args.domain == "muse":
cmd_muse_dispatch(args)
elif args.domain in ("docs", "doc"):
cmd_docs_dispatch(args)
elif args.domain == "sysop":
act = getattr(args, "sysop_action", None)
if act == "install":
cmd_sysop_install(args)
else:
parser.print_help()
else:
parser.print_help()
if __name__ == "__main__":
main()