-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathagentbox
More file actions
executable file
·252 lines (215 loc) · 10.2 KB
/
agentbox
File metadata and controls
executable file
·252 lines (215 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#!/usr/bin/env bash
# agentbox — spawn, manage, and connect to ephemeral AgentBox containers
# local (Docker) or remote (Azure Container Instances)
set -euo pipefail
AGENTBOX_IMAGE="${AGENTBOX_IMAGE:-ghcr.io/networg/agentbox:latest}"
AGENTBOX_RG="${AGENTBOX_RG:-agentbox-containers}"
AGENTBOX_LOCATION="${AGENTBOX_LOCATION:-westeurope}"
META_DIR="$HOME/.agentbox"
mkdir -p "$META_DIR"
# ── Helpers ───────────────────────────────────────────────────────────────────
_random_name() { echo "agentbox-$(openssl rand -hex 4)"; }
_save_meta() { echo "$1|$2|$3|$4|$5" > "$META_DIR/$6"; }
# _save_meta type fqdn terminal_port code_port proxy_port name
_load_meta() { [[ -f "$META_DIR/$1" ]] && cat "$META_DIR/$1" || echo ""; }
_usage() {
cat <<EOF
AgentBox — ephemeral dev containers for your team
Usage: agentbox <command> [options]
Commands:
spawn [NAME] [--azure] Start a new AgentBox
list List all running AgentBoxes
kill <NAME> [--azure] Destroy an AgentBox
open <NAME> Open VS Code (code-server) in browser
term <NAME> Open web terminal in browser
logs <NAME> Tail container logs
Options for spawn:
NAME Container name (default: agentbox-<random>)
--azure Deploy to Azure Container Instances instead of local Docker
Environment variables:
AGENTBOX_IMAGE Image to use (default: $AGENTBOX_IMAGE)
AGENTBOX_RG Azure resource group (default: $AGENTBOX_RG)
AGENTBOX_LOCATION Azure region (default: $AGENTBOX_LOCATION)
GH_TOKEN GitHub token — forwarded securely into the container
EOF
}
# ── spawn local ───────────────────────────────────────────────────────────────
_spawn_local() {
local name="$1"
echo "🚀 Starting AgentBox '$name'..."
docker run -d \
--name "$name" \
--cap-add=SYS_ADMIN \
--shm-size=1g \
-p 0:80 \
-p 0:7681 \
-p 0:8080 \
${GH_TOKEN:+-e "GH_TOKEN=$GH_TOKEN"} \
"$AGENTBOX_IMAGE" > /dev/null
sleep 3
local proxy_port; proxy_port=$(docker port "$name" 80/tcp | cut -d: -f2)
local term_port; term_port=$(docker port "$name" 7681/tcp | cut -d: -f2)
local code_port; code_port=$(docker port "$name" 8080/tcp | cut -d: -f2)
echo ""
echo " ✅ AgentBox '$name' ready"
echo " 💻 VS Code : http://localhost:$proxy_port"
echo " 🖥 Terminal : http://localhost:$proxy_port/terminal/"
echo " (direct) VS Code : http://localhost:$code_port"
echo " (direct) Terminal : http://localhost:$term_port"
echo ""
echo " Destroy with: agentbox kill $name"
_save_meta "local" "" "$term_port" "$code_port" "$name" "$proxy_port"
}
# ── spawn azure ───────────────────────────────────────────────────────────────
_spawn_azure() {
local name="$1"
# Ensure Microsoft.ContainerInstance provider is registered
local state
state=$(az provider show -n Microsoft.ContainerInstance --query registrationState -o tsv 2>/dev/null || echo "NotRegistered")
if [[ "$state" != "Registered" ]]; then
echo "📋 Registering Microsoft.ContainerInstance provider..."
az provider register --namespace Microsoft.ContainerInstance --output none 2>/dev/null
for _ in $(seq 1 30); do
state=$(az provider show -n Microsoft.ContainerInstance --query registrationState -o tsv 2>/dev/null)
[[ "$state" == "Registered" ]] && break
sleep 10
done
[[ "$state" != "Registered" ]] && { echo "❌ Provider registration timed out. Try again later."; exit 1; }
echo "✅ Provider registered."
fi
echo "☁️ Deploying AgentBox '$name' to Azure ACI..."
printf " Region : %s\n" "$AGENTBOX_LOCATION"
printf " Group : %s\n" "$AGENTBOX_RG"
printf " Image : %s\n" "$AGENTBOX_IMAGE"
printf " Cost : ~\$0.03/hr (0.5 vCPU · 1 GB RAM) — delete when done!\n\n"
az group create --name "$AGENTBOX_RG" --location "$AGENTBOX_LOCATION" \
--output none --only-show-errors 2>/dev/null || true
# Secure env vars (hidden from az container show output)
local sec_args=()
[[ -n "${GH_TOKEN:-}" ]] && sec_args+=(GH_TOKEN="$GH_TOKEN")
az container create \
--resource-group "$AGENTBOX_RG" \
--name "$name" \
--image "$AGENTBOX_IMAGE" \
--cpu 0.5 \
--memory 1 \
--dns-name-label "$name" \
--ports 80 \
--os-type Linux \
${sec_args:+--secure-environment-variables "${sec_args[@]}"} \
--output none \
--only-show-errors
local fqdn
fqdn=$(az container show \
--resource-group "$AGENTBOX_RG" \
--name "$name" \
--query ipAddress.fqdn -o tsv)
echo ""
echo " ✅ AgentBox '$name' ready on Azure"
echo " 💻 VS Code : http://$fqdn"
echo " 🖥 Terminal : http://$fqdn/terminal/"
echo ""
echo " ⚠️ Delete when done: agentbox kill $name --azure"
_save_meta "azure" "$fqdn" "" "" "" "$name"
}
# ── list ──────────────────────────────────────────────────────────────────────
_list() {
echo "── Local (Docker) ───────────────────────────────────────────────────"
docker ps --filter "ancestor=$AGENTBOX_IMAGE" \
--format " {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || echo " (docker not available)"
echo ""
echo "── Azure ACI ($AGENTBOX_RG) ─────────────────────────────────────────"
if command -v az &>/dev/null; then
az container list \
--resource-group "$AGENTBOX_RG" \
--query "[].{Name:name, State:instanceView.state, URL:ipAddress.fqdn}" \
-o table 2>/dev/null || echo " (group not found or not logged in)"
else
echo " (az not installed)"
fi
}
# ── kill ──────────────────────────────────────────────────────────────────────
_kill() {
local name="$1" azure="${2:-}"
if [[ "$azure" == "--azure" ]]; then
echo "🗑 Deleting Azure AgentBox '$name'..."
az container delete --resource-group "$AGENTBOX_RG" --name "$name" \
--yes --output none --only-show-errors
echo "✅ Deleted."
else
echo "🗑 Removing local AgentBox '$name'..."
docker rm -f "$name" > /dev/null
echo "✅ Done."
fi
rm -f "$META_DIR/$name"
}
# ── open (VS Code) ───────────────────────────────────────────────────────────
_open() {
local name="$1"
local meta; meta=$(_load_meta "$name")
[[ -z "$meta" ]] && { echo "❌ Unknown AgentBox '$name'. Run: agentbox list"; exit 1; }
local type fqdn _ __ proxy_port
IFS='|' read -r type fqdn _ __ proxy_port <<< "$meta"
local url
[[ "$type" == "azure" ]] && url="http://$fqdn" || url="http://localhost:${proxy_port:-8080}"
echo "💻 $url"
open "$url" 2>/dev/null || xdg-open "$url" 2>/dev/null || true
}
# ── term (web terminal) ──────────────────────────────────────────────────────
_term() {
local name="$1"
local meta; meta=$(_load_meta "$name")
[[ -z "$meta" ]] && { echo "❌ Unknown AgentBox '$name'. Run: agentbox list"; exit 1; }
local type fqdn _ __ proxy_port
IFS='|' read -r type fqdn _ __ proxy_port <<< "$meta"
local url
[[ "$type" == "azure" ]] && url="http://$fqdn/terminal/" || url="http://localhost:${proxy_port:-7681}/terminal/"
echo "🖥 $url"
open "$url" 2>/dev/null || xdg-open "$url" 2>/dev/null || true
}
# ── logs ──────────────────────────────────────────────────────────────────────
_logs() {
local name="$1"
local meta; meta=$(_load_meta "$name")
local type; IFS='|' read -r type _ <<< "$meta"
if [[ "$type" == "azure" ]]; then
az container logs --resource-group "$AGENTBOX_RG" --name "$name" --follow
else
docker logs -f "$name"
fi
}
# ── main ──────────────────────────────────────────────────────────────────────
CMD="${1:-help}"; shift || true
case "$CMD" in
spawn)
NAME="" AZURE=false
while [[ $# -gt 0 ]]; do
case "$1" in
--azure) AZURE=true; shift ;;
--*) echo "Unknown flag: $1"; _usage; exit 1 ;;
*) NAME="$1"; shift ;;
esac
done
[[ -z "$NAME" ]] && NAME=$(_random_name)
[[ "$AZURE" == "true" ]] && _spawn_azure "$NAME" || _spawn_local "$NAME"
;;
list) _list ;;
kill)
[[ -z "${1:-}" ]] && { echo "Usage: agentbox kill <name> [--azure]"; exit 1; }
_kill "$1" "${2:-}"
;;
open)
[[ -z "${1:-}" ]] && { echo "Usage: agentbox open <name>"; exit 1; }
_open "$1"
;;
term)
[[ -z "${1:-}" ]] && { echo "Usage: agentbox term <name>"; exit 1; }
_term "$1"
;;
logs)
[[ -z "${1:-}" ]] && { echo "Usage: agentbox logs <name>"; exit 1; }
_logs "$1"
;;
help|--help|-h) _usage ;;
*) echo "Unknown command: $CMD"; _usage; exit 1 ;;
esac