2026-10-04 23:30:18 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# box-relay.sh — Lightweight Box Relay Client for Fleet Agent Containers.
|
|
|
|
|
#
|
|
|
|
|
# Enables fleet agents (646, pip, muse, opm) to access muse-cli level tools,
|
|
|
|
|
# spawn subagents, send sidechat DMs, and inspect threads over the secure
|
|
|
|
|
# exec-constrained HTTPS relay endpoint.
|
|
|
|
|
#
|
|
|
|
|
# Supports Bearer Token (EXEC_TOKEN or ~/.exec-token) AND SSH signature auth.
|
|
|
|
|
# Endpoint: https://exec.muse-dev.online/exec (or Tailscale https://100.123.153.75:8444/exec)
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
EXEC_URL="${EXEC_URL:-https://exec.muse-dev.online/exec}"
|
|
|
|
|
AGENT="${BOX_AGENT:-${AGENT_NAME:-}}"
|
|
|
|
|
TOKEN="${EXEC_TOKEN:-}"
|
|
|
|
|
|
|
|
|
|
if [ -z "$TOKEN" ] && [ -f "$HOME/.exec-token" ]; then
|
|
|
|
|
TOKEN="$(cat "$HOME/.exec-token" | tr -d '[:space:]')"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Detect agent identity if not set
|
|
|
|
|
if [ -z "$AGENT" ]; then
|
|
|
|
|
if [ -f "$HOME/.agent-name" ]; then
|
|
|
|
|
AGENT="$(cat "$HOME/.agent-name" | tr -d '[:space:]')"
|
|
|
|
|
elif echo "$HOSTNAME" | grep -qi "646"; then
|
|
|
|
|
AGENT="646"
|
|
|
|
|
elif echo "$HOSTNAME" | grep -qi "pip"; then
|
|
|
|
|
AGENT="pip"
|
|
|
|
|
elif echo "$HOSTNAME" | grep -qi "muse"; then
|
|
|
|
|
AGENT="muse"
|
|
|
|
|
elif echo "$HOSTNAME" | grep -qi "opm"; then
|
|
|
|
|
AGENT="opm"
|
2026-10-05 01:53:23 +00:00
|
|
|
elif echo "$HOSTNAME" | grep -qi "dev"; then
|
|
|
|
|
AGENT="dev"
|
|
|
|
|
elif echo "$HOSTNAME" | grep -qi "def"; then
|
|
|
|
|
AGENT="def"
|
2026-10-04 23:30:18 +00:00
|
|
|
else
|
|
|
|
|
AGENT="646"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Helper: POST to exec endpoint
|
|
|
|
|
call_exec() {
|
|
|
|
|
local op="$1"
|
|
|
|
|
local args_json="$2"
|
|
|
|
|
|
|
|
|
|
if [ -n "$TOKEN" ]; then
|
|
|
|
|
# Bearer token auth
|
|
|
|
|
local body
|
|
|
|
|
body=$(python3 -c "import json, sys; print(json.dumps({'op': sys.argv[1], 'args': json.loads(sys.argv[2])}))" "$op" "$args_json")
|
|
|
|
|
local res
|
|
|
|
|
res=$(curl -sk -sS -X POST "$EXEC_URL" \
|
|
|
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) Box-Relay/1.0" \
|
|
|
|
|
--data "$body")
|
|
|
|
|
echo "$res" | python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
try:
|
|
|
|
|
d = json.load(sys.stdin)
|
|
|
|
|
if 'stdout' in d:
|
|
|
|
|
sys.stdout.write(d['stdout'])
|
|
|
|
|
elif 'error' in d:
|
|
|
|
|
sys.stderr.write('Error: ' + str(d['error']) + '\n')
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
else:
|
|
|
|
|
print(json.dumps(d, indent=2))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(sys.stdin.read())
|
|
|
|
|
"
|
|
|
|
|
else
|
|
|
|
|
# Signature auth fallback
|
|
|
|
|
local key="${SSH_KEY:-$HOME/.ssh/id_frontdoor}"
|
|
|
|
|
if [ ! -f "$key" ] && [ -f "$HOME/.ssh/id_ed25519" ]; then
|
|
|
|
|
key="$HOME/.ssh/id_ed25519"
|
|
|
|
|
fi
|
|
|
|
|
local ident="operator-$AGENT"
|
2026-10-05 01:53:23 +00:00
|
|
|
if [ "$AGENT" = "super" ]; then
|
|
|
|
|
ident="super"
|
|
|
|
|
fi
|
2026-10-04 23:30:18 +00:00
|
|
|
local ts
|
|
|
|
|
ts=$(date +%s)
|
|
|
|
|
local nonce
|
|
|
|
|
nonce=$(python3 -c "import secrets; print(secrets.token_hex(16))")
|
|
|
|
|
local payload
|
|
|
|
|
payload=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
op, args_json, ts, nonce = sys.argv[1:5]
|
|
|
|
|
args = json.loads(args_json)
|
|
|
|
|
print(json.dumps({'op': op, 'args': args, 'ts': int(ts), 'nonce': nonce}))
|
|
|
|
|
" "$op" "$args_json" "$ts" "$nonce")
|
|
|
|
|
local sig
|
|
|
|
|
sig=$(printf '%s' "$payload" | ssh-keygen -Y sign -f "$key" -n exec-constrained 2>/dev/null)
|
|
|
|
|
local body
|
|
|
|
|
body=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
ident, payload, sig = sys.argv[1:4]
|
|
|
|
|
print(json.dumps({'identity': ident, 'payload': payload, 'signature': sig}))
|
|
|
|
|
" "$ident" "$payload" "$sig")
|
|
|
|
|
local res
|
|
|
|
|
res=$(curl -sk -sS -X POST "$EXEC_URL" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) Box-Relay/1.0" \
|
|
|
|
|
--data "$body")
|
|
|
|
|
echo "$res" | python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
try:
|
|
|
|
|
d = json.load(sys.stdin)
|
|
|
|
|
if 'stdout' in d:
|
|
|
|
|
sys.stdout.write(d['stdout'])
|
|
|
|
|
elif 'error' in d:
|
|
|
|
|
sys.stderr.write('Error: ' + str(d['error']) + '\n')
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
else:
|
|
|
|
|
print(json.dumps(d, indent=2))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(sys.stdin.read())
|
|
|
|
|
"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd="${1:-help}"
|
|
|
|
|
shift || true
|
|
|
|
|
|
|
|
|
|
case "$cmd" in
|
|
|
|
|
subagent)
|
|
|
|
|
sub="${1:-help}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
spawn)
|
|
|
|
|
title="subagent"
|
|
|
|
|
wait=0
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--title) title="$2"; shift 2 ;;
|
|
|
|
|
--wait) wait="$2"; shift 2 ;;
|
|
|
|
|
--agent) AGENT="$2"; shift 2 ;;
|
|
|
|
|
*) break ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
prompt="${1:?usage: box subagent spawn [--title <title>] [--wait <seconds>] <prompt>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1], 'title': sys.argv[2], 'prompt': sys.argv[3], 'wait': int(sys.argv[4])}))" "$AGENT" "$title" "$prompt" "$wait")
|
|
|
|
|
call_exec "subagent.spawn" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box subagent spawn [--title <title>] [--wait <seconds>] <prompt>"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
deploy)
|
|
|
|
|
sub="${1:-help}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
subagent)
|
|
|
|
|
title="subagent"
|
|
|
|
|
wait=0
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--title) title="$2"; shift 2 ;;
|
|
|
|
|
--wait) wait="$2"; shift 2 ;;
|
|
|
|
|
--agent) AGENT="$2"; shift 2 ;;
|
|
|
|
|
*) break ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
prompt="${1:?usage: box deploy subagent [--title <title>] [--wait <seconds>] <prompt>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1], 'title': sys.argv[2], 'prompt': sys.argv[3], 'wait': int(sys.argv[4])}))" "$AGENT" "$title" "$prompt" "$wait")
|
|
|
|
|
call_exec "subagent.spawn" "$args"
|
|
|
|
|
;;
|
|
|
|
|
pipeline)
|
|
|
|
|
name="${1:?usage: box deploy pipeline <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "pipeline.run" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box deploy subagent|pipeline ..."
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
dm)
|
|
|
|
|
sub="${1:-help}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
send)
|
|
|
|
|
to=""
|
|
|
|
|
target=""
|
|
|
|
|
from_agent="$AGENT"
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--to) to="$2"; shift 2 ;;
|
|
|
|
|
--target) target="$2"; shift 2 ;;
|
|
|
|
|
--agent|--from) from_agent="$2"; shift 2 ;;
|
|
|
|
|
*) break ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
msg="${1:?usage: box dm send --to <agent> [--target <target>] <message>}"
|
|
|
|
|
to="${to:-$AGENT}"
|
|
|
|
|
target="${target:-$AGENT-pip}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1], 'to': sys.argv[2], 'target': sys.argv[3], 'message': sys.argv[4]}))" "$from_agent" "$to" "$target" "$msg")
|
|
|
|
|
call_exec "dm.send" "$args"
|
|
|
|
|
;;
|
|
|
|
|
read)
|
|
|
|
|
target="${1:-main}"
|
|
|
|
|
limit="${2:-10}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1], 'target': sys.argv[2], 'limit': int(sys.argv[3])}))" "$AGENT" "$target" "$limit")
|
|
|
|
|
call_exec "dm.read" "$args"
|
|
|
|
|
;;
|
2026-10-07 00:25:51 +00:00
|
|
|
log)
|
|
|
|
|
limit=""
|
|
|
|
|
log_agent=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--agent) log_agent="$2"; shift 2 ;;
|
|
|
|
|
*) if [ -z "$limit" ]; then limit="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
limit="${limit:-20}"
|
|
|
|
|
args=$(python3 -c "import json,sys; lim=int(sys.argv[1]); ag=sys.argv[2]; print(json.dumps({'limit':lim,**({'agent':ag} if ag else {})}))" "$limit" "$log_agent")
|
|
|
|
|
call_exec "dm.log" "$args"
|
|
|
|
|
;;
|
|
|
|
|
ack)
|
|
|
|
|
to=""
|
|
|
|
|
from_agent=""
|
|
|
|
|
sidechat=""
|
|
|
|
|
allow_main=""
|
|
|
|
|
ref_id=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--to) to="$2"; shift 2 ;;
|
|
|
|
|
--sender|--from) from_agent="$2"; shift 2 ;;
|
|
|
|
|
--sidechat) sidechat="$2"; shift 2 ;;
|
|
|
|
|
--allow-main-chat) allow_main="1"; shift ;;
|
|
|
|
|
*) if [ -z "$ref_id" ]; then ref_id="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
ref_id="${ref_id:?usage: box dm ack <id> --to <agent> --sender <agent> [--sidechat <name>] [--allow-main-chat]}"
|
|
|
|
|
from_agent="${from_agent:-$AGENT}"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
ref, to, sender, sc, main = sys.argv[1:6]
|
|
|
|
|
args = {'id': ref, 'to': to, 'sender': sender}
|
|
|
|
|
if sc:
|
|
|
|
|
args['sidechat'] = sc
|
|
|
|
|
if main:
|
|
|
|
|
args['allow_main_chat'] = True
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$ref_id" "$to" "$from_agent" "$sidechat" "$allow_main")
|
|
|
|
|
call_exec "dm.ack" "$args"
|
|
|
|
|
;;
|
2026-10-04 23:30:18 +00:00
|
|
|
*)
|
2026-10-07 00:25:51 +00:00
|
|
|
echo "Usage: box dm send|read|log|ack ..."
|
2026-10-04 23:30:18 +00:00
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
2026-10-07 00:25:51 +00:00
|
|
|
notify)
|
|
|
|
|
target_agent="${1:?usage: box notify <agent> [--sidechat <name>] [--sender <agent>] <message...>}"
|
|
|
|
|
shift
|
|
|
|
|
sidechat=""
|
|
|
|
|
sender=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--sidechat) sidechat="$2"; shift 2 ;;
|
|
|
|
|
--sender|--from) sender="$2"; shift 2 ;;
|
|
|
|
|
*) break ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
msg="${*:?usage: box notify <agent> [--sidechat <name>] [--sender <agent>] <message...>}"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
agent, message, sc, sender = sys.argv[1:5]
|
|
|
|
|
args = {'agent': agent, 'message': message}
|
|
|
|
|
if sc:
|
|
|
|
|
args['sidechat'] = sc
|
|
|
|
|
if sender:
|
|
|
|
|
args['sender'] = sender
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$target_agent" "$msg" "$sidechat" "$sender")
|
|
|
|
|
call_exec "notify.send" "$args"
|
|
|
|
|
;;
|
2026-10-04 23:30:18 +00:00
|
|
|
thread)
|
|
|
|
|
sub="${1:-list}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
list)
|
|
|
|
|
target_agent="${1:-$AGENT}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1]}))" "$target_agent")
|
|
|
|
|
call_exec "thread.list" "$args"
|
|
|
|
|
;;
|
|
|
|
|
view)
|
2026-10-05 01:53:23 +00:00
|
|
|
target_agent="$AGENT"
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--agent) target_agent="$2"; shift 2 ;;
|
|
|
|
|
*) break ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
if [ $# -ge 2 ] && echo " 646 opm pip muse dev def " | grep -q " $1 "; then
|
|
|
|
|
target_agent="$1"
|
|
|
|
|
shift
|
|
|
|
|
fi
|
|
|
|
|
thread_id="${1:?usage: box thread view [<agent>] <thread_id> [limit]}"
|
2026-10-04 23:30:18 +00:00
|
|
|
limit="${2:-15}"
|
2026-10-05 01:53:23 +00:00
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1], 'thread': sys.argv[2], 'limit': int(sys.argv[3])}))" "$target_agent" "$thread_id" "$limit")
|
2026-10-04 23:30:18 +00:00
|
|
|
call_exec "thread.view" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box thread list|view ..."
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
2026-10-05 03:41:43 +00:00
|
|
|
cron)
|
|
|
|
|
sub="${1:-runs}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
runs|list)
|
|
|
|
|
call_exec "cron.runs" "{}"
|
|
|
|
|
;;
|
|
|
|
|
status)
|
|
|
|
|
name="${1:-heartbeat}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.status" "$args"
|
|
|
|
|
;;
|
|
|
|
|
view)
|
|
|
|
|
name="${1:?usage: box cron view <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.view" "$args"
|
|
|
|
|
;;
|
|
|
|
|
run)
|
|
|
|
|
name="${1:?usage: box cron run <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'job': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.run" "$args"
|
|
|
|
|
;;
|
2026-10-07 00:25:51 +00:00
|
|
|
put)
|
|
|
|
|
name="${1:?usage: box cron put <name> '<json-definition>'}"
|
|
|
|
|
json_def="${2:?usage: box cron put <name> '<json-definition>'}"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
try:
|
|
|
|
|
definition = json.loads(sys.argv[2])
|
|
|
|
|
except Exception as e:
|
|
|
|
|
sys.stderr.write('invalid job JSON: %s\n' % e)
|
|
|
|
|
sys.exit(2)
|
|
|
|
|
print(json.dumps({'name': sys.argv[1], 'definition': definition}))
|
|
|
|
|
" "$name" "$json_def")
|
|
|
|
|
call_exec "job.put" "$args"
|
|
|
|
|
;;
|
|
|
|
|
trigger)
|
|
|
|
|
name="${1:?usage: box cron trigger <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "job.trigger" "$args"
|
|
|
|
|
;;
|
|
|
|
|
chain)
|
|
|
|
|
from_job="${1:?usage: box cron chain <from> <to> [--on-failure]}"
|
|
|
|
|
shift || true
|
|
|
|
|
on_failure=""
|
|
|
|
|
to_job=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--on-failure) on_failure="1"; shift ;;
|
|
|
|
|
*) if [ -z "$to_job" ]; then to_job="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
to_job="${to_job:?usage: box cron chain <from> <to> [--on-failure]}"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
frm, to, onfail = sys.argv[1:4]
|
|
|
|
|
args = {'from': frm, 'to': to}
|
|
|
|
|
if onfail:
|
|
|
|
|
args['on_failure'] = True
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$from_job" "$to_job" "$on_failure")
|
|
|
|
|
call_exec "job.chain" "$args"
|
|
|
|
|
;;
|
|
|
|
|
next)
|
|
|
|
|
job_id=""
|
|
|
|
|
success=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--success) success="1"; shift ;;
|
|
|
|
|
--fail) success="0"; shift ;;
|
|
|
|
|
*) if [ -z "$job_id" ]; then job_id="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
job_id="${job_id:?usage: box cron next <job-id> [--success|--fail]}"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
jid, success = sys.argv[1:3]
|
|
|
|
|
args = {'job_id': jid}
|
|
|
|
|
if success == '1':
|
|
|
|
|
args['success'] = True
|
|
|
|
|
elif success == '0':
|
|
|
|
|
args['success'] = False
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$job_id" "$success")
|
|
|
|
|
call_exec "job.next" "$args"
|
|
|
|
|
;;
|
2026-10-05 04:55:20 +00:00
|
|
|
timer-create)
|
|
|
|
|
name="${1:?usage: box cron timer-create <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.timer_create" "$args"
|
|
|
|
|
;;
|
|
|
|
|
timer-start)
|
|
|
|
|
name="${1:?usage: box cron timer-start <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.timer_start" "$args"
|
|
|
|
|
;;
|
2026-10-05 03:41:43 +00:00
|
|
|
*)
|
2026-10-07 00:25:51 +00:00
|
|
|
echo "Usage: box cron runs|status|view|run|put|trigger|chain|next|timer-create|timer-start ..."
|
2026-10-05 04:55:20 +00:00
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
timer)
|
|
|
|
|
sub="${1:-list}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
create|set)
|
|
|
|
|
name="${1:?usage: box timer create <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.timer_create" "$args"
|
|
|
|
|
;;
|
|
|
|
|
start|enable)
|
|
|
|
|
name="${1:?usage: box timer start <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.timer_start" "$args"
|
|
|
|
|
;;
|
2026-10-07 00:25:51 +00:00
|
|
|
stop)
|
|
|
|
|
name="${1:?usage: box timer stop <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.timer_stop" "$args"
|
|
|
|
|
;;
|
|
|
|
|
disable)
|
|
|
|
|
name="${1:?usage: box timer disable <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.timer_disable" "$args"
|
|
|
|
|
;;
|
2026-10-05 04:55:20 +00:00
|
|
|
status|view|list)
|
|
|
|
|
name="${1:-heartbeat}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "cron.status" "$args"
|
|
|
|
|
;;
|
2026-10-05 05:24:45 +00:00
|
|
|
in|delay)
|
|
|
|
|
min="${1:?usage: box timer in <minutes> <prompt>}"
|
|
|
|
|
shift
|
|
|
|
|
prompt="${*:?usage: box timer in <minutes> <prompt>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1], 'in_m': float(sys.argv[2]), 'prompt': sys.argv[3]}))" "$AGENT" "$min" "$prompt")
|
|
|
|
|
call_exec "followup.create" "$args"
|
|
|
|
|
;;
|
2026-10-05 04:55:20 +00:00
|
|
|
*)
|
2026-10-07 00:25:51 +00:00
|
|
|
echo "Usage: box timer create|start|stop|enable|disable|status <name> OR box timer in <minutes> <prompt>"
|
2026-10-05 05:24:45 +00:00
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
followup)
|
|
|
|
|
sub="${1:-create}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
create|set|schedule)
|
|
|
|
|
min="${1:?usage: box followup create <minutes> <prompt>}"
|
|
|
|
|
shift
|
|
|
|
|
prompt="${*:?usage: box followup create <minutes> <prompt>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1], 'in_m': float(sys.argv[2]), 'prompt': sys.argv[3]}))" "$AGENT" "$min" "$prompt")
|
|
|
|
|
call_exec "followup.create" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box followup create <minutes> <prompt>"
|
2026-10-05 04:55:20 +00:00
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
swarm)
|
|
|
|
|
sub="${1:-list}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
spawn)
|
|
|
|
|
count="${1:?usage: box swarm spawn <count> <task...>}"
|
|
|
|
|
shift
|
|
|
|
|
task="$*"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'count': int(sys.argv[1]), 'task': sys.argv[2]}))" "$count" "$task")
|
|
|
|
|
call_exec "swarm.spawn" "$args"
|
|
|
|
|
;;
|
|
|
|
|
status)
|
|
|
|
|
sid="${1:?usage: box swarm status <swarm_id>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'swarm_id': sys.argv[1]}))" "$sid")
|
|
|
|
|
call_exec "swarm.status" "$args"
|
|
|
|
|
;;
|
|
|
|
|
list)
|
|
|
|
|
call_exec "swarm.list" "{}"
|
|
|
|
|
;;
|
2026-10-05 05:39:36 +00:00
|
|
|
results)
|
|
|
|
|
sid="${1:?usage: box swarm results <swarm_id>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'swarm_id': sys.argv[1]}))" "$sid")
|
|
|
|
|
call_exec "swarm.results" "$args"
|
|
|
|
|
;;
|
2026-10-05 04:55:20 +00:00
|
|
|
*)
|
2026-10-05 05:39:36 +00:00
|
|
|
echo "Usage: box swarm spawn|status|results|list ..."
|
2026-10-05 03:41:43 +00:00
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
2026-10-07 00:25:51 +00:00
|
|
|
loop)
|
|
|
|
|
sub="${1:?usage: box loop remediate|resolve ...}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
remediate)
|
|
|
|
|
dry=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--dry-run) dry="1"; shift ;;
|
|
|
|
|
*) break ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
if [ -n "$dry" ]; then
|
|
|
|
|
args='{"dry_run": true}'
|
|
|
|
|
else
|
|
|
|
|
args='{}'
|
|
|
|
|
fi
|
|
|
|
|
call_exec "loop.remediate" "$args"
|
|
|
|
|
;;
|
|
|
|
|
resolve)
|
|
|
|
|
dm_id="${1:?usage: box loop resolve <dm_id> [note...]}"
|
|
|
|
|
shift || true
|
|
|
|
|
note="$*"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
dm_id, note = sys.argv[1:3]
|
|
|
|
|
args = {'dm_id': dm_id}
|
|
|
|
|
if note:
|
|
|
|
|
args['note'] = note
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$dm_id" "$note")
|
|
|
|
|
call_exec "loop.resolve" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box loop remediate [--dry-run] OR box loop resolve <dm_id> [note...]"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
strat)
|
|
|
|
|
sub="${1:?usage: box strat set|reset ...}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
set)
|
|
|
|
|
stype="${1:?usage: box strat set <type> [options]}"
|
|
|
|
|
shift || true
|
|
|
|
|
subtype=""
|
|
|
|
|
agent=""
|
|
|
|
|
track=""
|
|
|
|
|
priority=""
|
|
|
|
|
timeout_s=""
|
|
|
|
|
nudges=""
|
|
|
|
|
escalate=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--subtype) subtype="$2"; shift 2 ;;
|
|
|
|
|
--agent) agent="$2"; shift 2 ;;
|
|
|
|
|
--track) track="$2"; shift 2 ;;
|
|
|
|
|
--priority) priority="$2"; shift 2 ;;
|
|
|
|
|
--timeout) timeout_s="$2"; shift 2 ;;
|
|
|
|
|
--nudges) nudges="$2"; shift 2 ;;
|
|
|
|
|
--escalate) escalate="$2"; shift 2 ;;
|
|
|
|
|
*) break ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
stype, subtype, agent, track, prio, timeout_s, nudges, esc = sys.argv[1:9]
|
|
|
|
|
args = {'type': stype}
|
|
|
|
|
if subtype:
|
|
|
|
|
args['subtype'] = subtype
|
|
|
|
|
if agent:
|
|
|
|
|
args['agent'] = agent
|
|
|
|
|
if track.lower() == 'true':
|
|
|
|
|
args['track'] = True
|
|
|
|
|
elif track.lower() == 'false':
|
|
|
|
|
args['track'] = False
|
|
|
|
|
elif track:
|
|
|
|
|
sys.stderr.write('track must be true|false\n')
|
|
|
|
|
sys.exit(2)
|
|
|
|
|
if prio:
|
|
|
|
|
args['priority'] = prio
|
|
|
|
|
if timeout_s:
|
|
|
|
|
args['timeout_s'] = int(timeout_s)
|
|
|
|
|
if nudges:
|
|
|
|
|
args['nudges'] = int(nudges)
|
|
|
|
|
if esc:
|
|
|
|
|
args['escalate'] = esc
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$stype" "$subtype" "$agent" "$track" "$priority" "$timeout_s" "$nudges" "$escalate")
|
|
|
|
|
call_exec "strat.set" "$args"
|
|
|
|
|
;;
|
|
|
|
|
reset)
|
|
|
|
|
stype="${1:?usage: box strat reset <type> [subtype] [--agent <agent>]}"
|
|
|
|
|
shift || true
|
|
|
|
|
subtype=""
|
|
|
|
|
agent=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--agent) agent="$2"; shift 2 ;;
|
|
|
|
|
*) if [ -z "$subtype" ]; then subtype="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
stype, subtype, agent = sys.argv[1:4]
|
|
|
|
|
args = {'type': stype}
|
|
|
|
|
if subtype:
|
|
|
|
|
args['subtype'] = subtype
|
|
|
|
|
if agent:
|
|
|
|
|
args['agent'] = agent
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$stype" "$subtype" "$agent")
|
|
|
|
|
call_exec "strat.reset" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box strat set <type> [options] OR box strat reset <type> [subtype] [--agent <agent>]"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
2026-10-05 03:41:43 +00:00
|
|
|
vars)
|
|
|
|
|
sub="${1:-list}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
list)
|
|
|
|
|
call_exec "vars.list" "{}"
|
|
|
|
|
;;
|
|
|
|
|
get)
|
|
|
|
|
name="${1:?usage: box vars get <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "vars.get" "$args"
|
|
|
|
|
;;
|
|
|
|
|
set)
|
|
|
|
|
name="${1:?usage: box vars set <name> <value>}"
|
|
|
|
|
val="${2:?usage: box vars set <name> <value>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1], 'value': sys.argv[2]}))" "$name" "$val")
|
|
|
|
|
call_exec "vars.set" "$args"
|
|
|
|
|
;;
|
2026-10-07 00:25:51 +00:00
|
|
|
reset)
|
|
|
|
|
name="${1:?usage: box vars reset <name>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'name': sys.argv[1]}))" "$name")
|
|
|
|
|
call_exec "vars.reset" "$args"
|
|
|
|
|
;;
|
|
|
|
|
rollback)
|
|
|
|
|
name="${1:?usage: box vars rollback <name> [revision]}"
|
|
|
|
|
rev="${2:-}"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
name, rev = sys.argv[1:3]
|
|
|
|
|
args = {'name': name}
|
|
|
|
|
if rev:
|
|
|
|
|
args['revision'] = int(rev) if rev.isdigit() else rev
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$name" "$rev")
|
|
|
|
|
call_exec "vars.rollback" "$args"
|
|
|
|
|
;;
|
2026-10-05 03:41:43 +00:00
|
|
|
*)
|
2026-10-07 00:25:51 +00:00
|
|
|
echo "Usage: box vars list|get|set|reset|rollback ..."
|
2026-10-05 03:41:43 +00:00
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
2026-10-05 03:51:43 +00:00
|
|
|
files)
|
|
|
|
|
sub="${1:-read}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
read)
|
|
|
|
|
path="${1:?usage: box files read <path> [lines=100]}"
|
|
|
|
|
lines="${2:-100}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'path': sys.argv[1], 'lines': int(sys.argv[2])}))" "$path" "$lines")
|
|
|
|
|
call_exec "files.read" "$args"
|
|
|
|
|
;;
|
|
|
|
|
write)
|
|
|
|
|
path="${1:?usage: box files write <path> <content>}"
|
|
|
|
|
content="${2:?usage: box files write <path> <content>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'path': sys.argv[1], 'content': sys.argv[2]}))" "$path" "$content")
|
|
|
|
|
call_exec "files.write" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box files read|write ..."
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
web)
|
|
|
|
|
sub="${1:-fetch}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
fetch)
|
|
|
|
|
url="${1:?usage: box web fetch <url>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'url': sys.argv[1]}))" "$url")
|
|
|
|
|
call_exec "web.fetch" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box web fetch <url>"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
service)
|
|
|
|
|
sub="${1:-status}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
status)
|
|
|
|
|
unit="${1:?usage: box service status <unit>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'unit': sys.argv[1]}))" "$unit")
|
|
|
|
|
call_exec "service.status" "$args"
|
|
|
|
|
;;
|
|
|
|
|
restart)
|
|
|
|
|
unit="${1:?usage: box service restart <unit>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'unit': sys.argv[1]}))" "$unit")
|
|
|
|
|
call_exec "service.restart" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box service status|restart <unit>"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
2026-10-07 00:25:51 +00:00
|
|
|
git)
|
|
|
|
|
sub="${1:-status}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
status)
|
|
|
|
|
call_exec "git.status" "{}"
|
|
|
|
|
;;
|
|
|
|
|
diff)
|
|
|
|
|
stat=""
|
|
|
|
|
path=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--stat) stat="1"; shift ;;
|
|
|
|
|
--path) path="$2"; shift 2 ;;
|
|
|
|
|
*) if [ -z "$path" ]; then path="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
stat, path = sys.argv[1:3]
|
|
|
|
|
args = {}
|
|
|
|
|
if stat:
|
|
|
|
|
args['stat'] = True
|
|
|
|
|
if path:
|
|
|
|
|
args['path'] = path
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$stat" "$path")
|
|
|
|
|
call_exec "git.diff" "$args"
|
|
|
|
|
;;
|
|
|
|
|
log)
|
|
|
|
|
limit=""
|
|
|
|
|
path=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--limit) limit="$2"; shift 2 ;;
|
|
|
|
|
--path) path="$2"; shift 2 ;;
|
|
|
|
|
*) if [ -z "$limit" ]; then limit="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
limit="${limit:-10}"
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
limit, path = sys.argv[1:3]
|
|
|
|
|
args = {'limit': int(limit)}
|
|
|
|
|
if path:
|
|
|
|
|
args['path'] = path
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$limit" "$path")
|
|
|
|
|
call_exec "git.log" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box git status|diff|log ..."
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
tests)
|
|
|
|
|
sub="${1:-run}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
run)
|
|
|
|
|
test_mod=""
|
|
|
|
|
filt=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--filter) filt="$2"; shift 2 ;;
|
|
|
|
|
*) if [ -z "$test_mod" ]; then test_mod="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
mod, filt = sys.argv[1:3]
|
|
|
|
|
args = {}
|
|
|
|
|
if mod:
|
|
|
|
|
args['test'] = mod
|
|
|
|
|
if filt:
|
|
|
|
|
args['filter'] = filt
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$test_mod" "$filt")
|
|
|
|
|
call_exec "tests.run" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box tests run [tests.<module>] [--filter <pattern>]"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
approvals)
|
|
|
|
|
sub="${1:-check}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
check)
|
|
|
|
|
node="${1:-}"
|
|
|
|
|
if [ -n "$node" ]; then
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'node': sys.argv[1]}))" "$node")
|
|
|
|
|
else
|
|
|
|
|
args="{}"
|
|
|
|
|
fi
|
|
|
|
|
call_exec "approval.check" "$args"
|
|
|
|
|
;;
|
|
|
|
|
allow)
|
|
|
|
|
node=""
|
|
|
|
|
message=""
|
|
|
|
|
main_chat=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--message) message="$2"; shift 2 ;;
|
|
|
|
|
--allow-main-chat) main_chat="1"; shift ;;
|
|
|
|
|
*) if [ -z "$node" ]; then node="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
node="${node:?usage: box approvals allow <node> --message <text> [--allow-main-chat]}"
|
|
|
|
|
[ -n "$message" ] || { echo "usage: box approvals allow <node> --message <text> [--allow-main-chat]" >&2; exit 2; }
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
node, message, main = sys.argv[1:4]
|
|
|
|
|
args = {'node': node, 'message': message}
|
|
|
|
|
if main:
|
|
|
|
|
args['allow_main_chat'] = True
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$node" "$message" "$main_chat")
|
|
|
|
|
call_exec "approval.allow" "$args"
|
|
|
|
|
;;
|
|
|
|
|
deny)
|
|
|
|
|
node=""
|
|
|
|
|
message=""
|
|
|
|
|
main_chat=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--message) message="$2"; shift 2 ;;
|
|
|
|
|
--allow-main-chat) main_chat="1"; shift 2 ;;
|
|
|
|
|
*) if [ -z "$node" ]; then node="$1"; fi; shift ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
node="${node:?usage: box approvals deny <node> --message <text> [--allow-main-chat]}"
|
|
|
|
|
[ -n "$message" ] || { echo "usage: box approvals deny <node> --message <text> [--allow-main-chat]" >&2; exit 2; }
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
node, message, main = sys.argv[1:4]
|
|
|
|
|
args = {'node': node, 'message': message}
|
|
|
|
|
if main:
|
|
|
|
|
args['allow_main_chat'] = True
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$node" "$message" "$main_chat")
|
|
|
|
|
call_exec "approval.deny" "$args"
|
|
|
|
|
;;
|
|
|
|
|
auto)
|
|
|
|
|
node="${1:-}"
|
|
|
|
|
if [ -n "$node" ]; then
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'node': sys.argv[1]}))" "$node")
|
|
|
|
|
else
|
|
|
|
|
args="{}"
|
|
|
|
|
fi
|
|
|
|
|
call_exec "approval.auto" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box approvals check|allow|deny|auto ..."
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
md)
|
|
|
|
|
sub="${1:-audit}"
|
|
|
|
|
shift || true
|
|
|
|
|
case "$sub" in
|
|
|
|
|
audit)
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
accts = [a for a in sys.argv[1:] if a]
|
|
|
|
|
print(json.dumps({'accounts': accts} if accts else {}))
|
|
|
|
|
" "$@")
|
|
|
|
|
call_exec "md.audit" "$args"
|
|
|
|
|
;;
|
|
|
|
|
list)
|
|
|
|
|
account="${1:?usage: box md list <account> [path]}"
|
|
|
|
|
path="${2:-}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'account': sys.argv[1], 'path': sys.argv[2]}))" "$account" "$path")
|
|
|
|
|
call_exec "md.list" "$args"
|
|
|
|
|
;;
|
|
|
|
|
read)
|
|
|
|
|
account="${1:?usage: box md read <account> <filename>}"
|
|
|
|
|
filename="${2:?usage: box md read <account> <filename>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'account': sys.argv[1], 'filename': sys.argv[2]}))" "$account" "$filename")
|
|
|
|
|
call_exec "md.read" "$args"
|
|
|
|
|
;;
|
|
|
|
|
diff)
|
|
|
|
|
account="${1:?usage: box md diff <account> <filename>}"
|
|
|
|
|
filename="${2:?usage: box md diff <account> <filename>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'account': sys.argv[1], 'filename': sys.argv[2]}))" "$account" "$filename")
|
|
|
|
|
call_exec "md.diff" "$args"
|
|
|
|
|
;;
|
|
|
|
|
pull)
|
|
|
|
|
account="${1:?usage: box md pull <account> <filename>}"
|
|
|
|
|
filename="${2:?usage: box md pull <account> <filename>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'account': sys.argv[1], 'filename': sys.argv[2]}))" "$account" "$filename")
|
|
|
|
|
call_exec "md.pull" "$args"
|
|
|
|
|
;;
|
|
|
|
|
inject-drive)
|
|
|
|
|
account="${1:?usage: box md inject-drive <account>}"
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'account': sys.argv[1]}))" "$account")
|
|
|
|
|
call_exec "md.inject_drive" "$args"
|
|
|
|
|
;;
|
|
|
|
|
sync-all)
|
|
|
|
|
call_exec "md.sync_all" "{}"
|
|
|
|
|
;;
|
|
|
|
|
amend)
|
|
|
|
|
filename="${1:?usage: box md amend <filename> (--content <text>|--file <path>) [--author <name>] [--reason <why>]}"
|
|
|
|
|
shift || true
|
|
|
|
|
content=""; content_src=""; author="operator"; reason=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--content) content="$2"; content_src="arg"; shift 2 ;;
|
|
|
|
|
--file) content="$2"; content_src="file"; shift 2 ;;
|
|
|
|
|
--author) author="$2"; shift 2 ;;
|
|
|
|
|
--reason) reason="$2"; shift 2 ;;
|
|
|
|
|
*) echo "usage: box md amend <filename> (--content <text>|--file <path>) [--author <name>] [--reason <why>]" >&2; exit 2 ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
[ -n "$content_src" ] || { echo "usage: box md amend <filename> (--content <text>|--file <path>) [--author <name>] [--reason <why>]" >&2; exit 2; }
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
fn, src, val, author, reason = sys.argv[1:6]
|
|
|
|
|
content = open(val, encoding='utf-8').read() if src == 'file' else val
|
|
|
|
|
args = {'filename': fn, 'content': content, 'author': author}
|
|
|
|
|
if reason:
|
|
|
|
|
args['reason'] = reason
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$filename" "$content_src" "$content" "$author" "$reason")
|
|
|
|
|
call_exec "md.amend" "$args"
|
|
|
|
|
;;
|
|
|
|
|
append)
|
|
|
|
|
filename="${1:?usage: box md append <filename> (--content <text>|--file <path>) [--author <name>] [--section <header>]}"
|
|
|
|
|
shift || true
|
|
|
|
|
text=""; text_src=""; author="operator"; section=""
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--content) text="$2"; text_src="arg"; shift 2 ;;
|
|
|
|
|
--file) text="$2"; text_src="file"; shift 2 ;;
|
|
|
|
|
--author) author="$2"; shift 2 ;;
|
|
|
|
|
--section) section="$2"; shift 2 ;;
|
|
|
|
|
*) echo "usage: box md append <filename> (--content <text>|--file <path>) [--author <name>] [--section <header>]" >&2; exit 2 ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
[ -n "$text_src" ] || { echo "usage: box md append <filename> (--content <text>|--file <path>) [--author <name>] [--section <header>]" >&2; exit 2; }
|
|
|
|
|
args=$(python3 -c "
|
|
|
|
|
import json, sys
|
|
|
|
|
fn, src, val, author, section = sys.argv[1:6]
|
|
|
|
|
text = open(val, encoding='utf-8').read() if src == 'file' else val
|
|
|
|
|
args = {'filename': fn, 'text': text, 'author': author}
|
|
|
|
|
if section:
|
|
|
|
|
args['section'] = section
|
|
|
|
|
print(json.dumps(args))
|
|
|
|
|
" "$filename" "$text_src" "$text" "$author" "$section")
|
|
|
|
|
call_exec "md.append" "$args"
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: box md audit|list|read|diff|pull|inject-drive|sync-all|amend|append ..."
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
unread)
|
|
|
|
|
target_agent="${1:-}"
|
|
|
|
|
if [ -n "$target_agent" ]; then
|
|
|
|
|
args=$(python3 -c "import json, sys; print(json.dumps({'agent': sys.argv[1]}))" "$target_agent")
|
|
|
|
|
else
|
|
|
|
|
args="{}"
|
|
|
|
|
fi
|
|
|
|
|
call_exec "fleet.unread" "$args"
|
|
|
|
|
;;
|
2026-10-05 05:36:28 +00:00
|
|
|
health|fleet-status)
|
2026-10-04 23:30:18 +00:00
|
|
|
call_exec "health.check" "{}"
|
|
|
|
|
;;
|
2026-10-05 05:36:28 +00:00
|
|
|
cdp-latency)
|
|
|
|
|
call_exec "cdp.latency" "{}"
|
|
|
|
|
;;
|
|
|
|
|
chrome-errors)
|
|
|
|
|
call_exec "chrome.errors" "{}"
|
|
|
|
|
;;
|
|
|
|
|
watchdog-alerts)
|
2026-10-05 05:39:36 +00:00
|
|
|
call_exec "watchdog.alerts" "{}"
|
|
|
|
|
;;
|
|
|
|
|
relay-health)
|
|
|
|
|
call_exec "relay.health" "{}"
|
2026-10-05 05:36:28 +00:00
|
|
|
;;
|
2026-10-05 05:40:46 +00:00
|
|
|
quality|quality-check)
|
|
|
|
|
call_exec "quality.check" "{}"
|
|
|
|
|
;;
|
2026-10-04 23:30:18 +00:00
|
|
|
ping)
|
|
|
|
|
call_exec "exec.ping" "{}"
|
|
|
|
|
;;
|
|
|
|
|
ops)
|
2026-10-05 01:53:23 +00:00
|
|
|
curl -sk -sS "${EXEC_URL%/exec}/ops" | python3 -m json.tool
|
2026-10-04 23:30:18 +00:00
|
|
|
;;
|
|
|
|
|
help|--help|-h)
|
|
|
|
|
cat <<EOF
|
|
|
|
|
Box Relay Client — Agent CLI for autonomous coordination
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
box subagent spawn [--title <title>] [--wait <s=0>] <prompt>
|
|
|
|
|
box deploy subagent [--title <title>] [--wait <s=0>] <prompt>
|
|
|
|
|
box deploy pipeline <name>
|
|
|
|
|
box dm send --to <agent> [--target <target>] <message>
|
|
|
|
|
box dm read [<target=main>] [<limit=10>]
|
2026-10-07 00:25:51 +00:00
|
|
|
box dm log [<limit=20>] [--agent <agent>]
|
|
|
|
|
box dm ack <id> --to <agent> --sender <agent> [--sidechat <name>]
|
|
|
|
|
box notify <agent> [--sidechat <name>] [--sender <agent>] <message...>
|
2026-10-04 23:30:18 +00:00
|
|
|
box thread list [<agent>]
|
|
|
|
|
box thread view <thread_id> [<limit=15>]
|
2026-10-05 03:41:43 +00:00
|
|
|
box cron runs
|
|
|
|
|
box cron status [<name=heartbeat>]
|
|
|
|
|
box cron view <name>
|
|
|
|
|
box cron run <name>
|
2026-10-07 00:25:51 +00:00
|
|
|
box cron put <name> '<json-definition>'
|
|
|
|
|
box cron trigger <name>
|
|
|
|
|
box cron chain <from> <to> [--on-failure]
|
|
|
|
|
box cron next <job-id> [--success|--fail]
|
|
|
|
|
box timer stop <name>
|
|
|
|
|
box timer disable <name>
|
2026-10-05 03:41:43 +00:00
|
|
|
box vars list
|
|
|
|
|
box vars get <name>
|
|
|
|
|
box vars set <name> <value>
|
2026-10-07 00:25:51 +00:00
|
|
|
box vars reset <name>
|
|
|
|
|
box vars rollback <name> [revision]
|
|
|
|
|
box strat set <type> [--subtype S] [--agent A] [--track b] [--priority p] [--timeout N] [--nudges N] [--escalate E]
|
|
|
|
|
box strat reset <type> [subtype] [--agent <agent>]
|
|
|
|
|
box loop remediate [--dry-run]
|
|
|
|
|
box loop resolve <dm_id> [note...]
|
2026-10-05 03:51:43 +00:00
|
|
|
box files read <path> [lines=100]
|
|
|
|
|
box files write <path> <content>
|
|
|
|
|
box web fetch <url>
|
|
|
|
|
box service status <unit>
|
|
|
|
|
box service restart <unit>
|
2026-10-07 00:25:51 +00:00
|
|
|
box git status
|
|
|
|
|
box git diff [--stat] [--path <path>]
|
|
|
|
|
box git log [<limit=10>] [--path <path>]
|
|
|
|
|
box tests run [tests.<module>] [--filter <pattern>]
|
|
|
|
|
box md audit [accounts...]
|
|
|
|
|
box md list <account> [path]
|
|
|
|
|
box md read <account> <filename>
|
|
|
|
|
box md diff <account> <filename>
|
|
|
|
|
box md pull <account> <filename>
|
|
|
|
|
box md inject-drive <account>
|
|
|
|
|
box md sync-all
|
|
|
|
|
box md amend <filename> (--content <text>|--file <path>) [--author <name>] [--reason <why>]
|
|
|
|
|
box md append <filename> (--content <text>|--file <path>) [--author <name>] [--section <header>]
|
|
|
|
|
box approvals check [node]
|
|
|
|
|
box approvals allow <node> --message <text> [--allow-main-chat]
|
|
|
|
|
box approvals deny <node> --message <text> [--allow-main-chat]
|
|
|
|
|
box approvals auto [node]
|
2026-10-04 23:30:18 +00:00
|
|
|
box health
|
2026-10-07 00:25:51 +00:00
|
|
|
box unread [<agent>]
|
2026-10-04 23:30:18 +00:00
|
|
|
box ping
|
|
|
|
|
box ops
|
|
|
|
|
|
|
|
|
|
Configuration:
|
|
|
|
|
EXEC_URL Endpoint (default: https://exec.muse-dev.online/exec)
|
|
|
|
|
EXEC_TOKEN Bearer token (or store in ~/.exec-token)
|
|
|
|
|
BOX_AGENT Agent identity (646, pip, muse, opm)
|
|
|
|
|
EOF
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Unknown command: $cmd (run 'box help')"
|
|
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|