fireclaw 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,18 +5,79 @@ set -euo pipefail
5
5
  VARS_FILE="$1"
6
6
  [[ -f "$VARS_FILE" ]] || { echo "Vars file missing: $VARS_FILE" >&2; exit 1; }
7
7
 
8
- set -a
9
- source "$VARS_FILE"
10
- set +a
8
+ cleanup_guest_tmp() {
9
+ if [[ "$VARS_FILE" == /tmp/provision.vars ]]; then
10
+ rm -f "$VARS_FILE"
11
+ fi
12
+ rm -f /tmp/provision-guest.sh
13
+ }
14
+ trap cleanup_guest_tmp EXIT
15
+
16
+ legacy_unquote_value() {
17
+ local value="$1"
18
+ local out="" ch inner
19
+ if [[ "$value" == "''" ]]; then
20
+ printf ''
21
+ return
22
+ fi
23
+ if [[ "$value" == \$\'*\' && ${#value} -ge 3 ]]; then
24
+ inner="${value:2:${#value}-3}"
25
+ printf '%b' "$inner"
26
+ return
27
+ fi
28
+ while [[ -n "$value" ]]; do
29
+ ch="${value:0:1}"
30
+ if [[ "$ch" == "\\" && ${#value} -gt 1 ]]; then
31
+ value="${value:1}"
32
+ out="${out}${value:0:1}"
33
+ else
34
+ out="${out}${ch}"
35
+ fi
36
+ value="${value:1}"
37
+ done
38
+ printf '%s' "$out"
39
+ }
40
+
41
+ load_vars_file() {
42
+ local format line key value
43
+ format="$(grep '^FIRECLAW_STATE_FORMAT=' "$VARS_FILE" | tail -n 1 | cut -d= -f2- || true)"
44
+ while IFS= read -r line || [[ -n "$line" ]]; do
45
+ [[ -n "$line" && "$line" != \#* ]] || continue
46
+ [[ "$line" == *=* ]] || { echo "Invalid vars entry in $VARS_FILE: $line" >&2; exit 1; }
47
+ key="${line%%=*}"
48
+ value="${line#*=}"
49
+ if [[ "$key" == "FIRECLAW_STATE_FORMAT" ]]; then
50
+ continue
51
+ fi
52
+ if [[ "$format" != "plain-v1" ]]; then
53
+ value="$(legacy_unquote_value "$value")"
54
+ fi
55
+ [[ "$value" != *$'\n'* && "$value" != *$'\r'* ]] || { echo "Invalid newline in vars value: $key" >&2; exit 1; }
56
+ case "$key" in
57
+ INSTANCE_ID|TELEGRAM_TOKEN|TELEGRAM_USERS|MODEL|SKILLS|GATEWAY_TOKEN|OPENCLAW_IMAGE|SKIP_BROWSER_INSTALL|DISK_SIZE|ANTHROPIC_API_KEY|OPENAI_API_KEY|MINIMAX_API_KEY)
58
+ printf -v "$key" '%s' "$value"
59
+ export "$key"
60
+ ;;
61
+ *)
62
+ echo "Unknown vars key in $VARS_FILE: $key" >&2
63
+ exit 1
64
+ ;;
65
+ esac
66
+ done < "$VARS_FILE"
67
+ }
68
+
69
+ load_vars_file
11
70
 
12
71
  require() { [[ -n "${!1:-}" ]] || { echo "Missing required var: $1" >&2; exit 1; }; }
13
72
 
14
73
  require INSTANCE_ID
15
- require TELEGRAM_TOKEN
16
74
  require MODEL
17
75
  require SKILLS
18
76
  require GATEWAY_TOKEN
19
77
  require OPENCLAW_IMAGE
78
+ if [[ -n "${TELEGRAM_TOKEN:-}" ]]; then
79
+ require TELEGRAM_USERS
80
+ fi
20
81
 
21
82
  [[ "$INSTANCE_ID" =~ ^[a-z0-9_-]+$ ]] || {
22
83
  echo "INSTANCE_ID must match [a-z0-9_-]+" >&2
@@ -30,10 +91,25 @@ TOOLS_DIR="/home/ubuntu/openclaw-${INSTANCE_ID}/tools"
30
91
  ENV_FILE="$CONFIG_ROOT/openclaw.env"
31
92
  GUEST_SERVICE="openclaw-${INSTANCE_ID}.service"
32
93
  HEALTH_SCRIPT="/usr/local/bin/openclaw-health-${INSTANCE_ID}.sh"
94
+ PLAYWRIGHT_FALLBACK_PACKAGE="${PLAYWRIGHT_FALLBACK_PACKAGE:-playwright@1.44.1}"
33
95
 
34
96
  log() { printf '==> %s\n' "$*"; }
35
97
  warn() { printf 'Warning: %s\n' "$*" >&2; }
36
98
 
99
+ csv_values() {
100
+ printf '%s' "$1" | tr ',' '\n' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; /^$/d'
101
+ }
102
+
103
+ csv_json_array() {
104
+ local values
105
+ values="$(csv_values "$1")"
106
+ if [[ -z "$values" ]]; then
107
+ printf '[]\n'
108
+ else
109
+ printf '%s\n' "$values" | jq -R . | jq -s .
110
+ fi
111
+ }
112
+
37
113
  wait_for_cloud_init() {
38
114
  if command -v cloud-init >/dev/null 2>&1; then
39
115
  log "Waiting for cloud-init to finish"
@@ -167,6 +243,18 @@ if ! command -v jq >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
167
243
  fi
168
244
  ensure_docker_daemon_config
169
245
 
246
+ skills_json="$(csv_json_array "${SKILLS:-}")"
247
+
248
+ telegram_allow_from_json="[]"
249
+ if [[ -n "${TELEGRAM_TOKEN:-}" ]]; then
250
+ telegram_users_values="$(csv_values "${TELEGRAM_USERS:-}")"
251
+ if [[ -z "$telegram_users_values" ]]; then
252
+ echo "TELEGRAM_USERS must include at least one allowed Telegram user ID; refusing to create an unreachable allowlist bot" >&2
253
+ exit 1
254
+ fi
255
+ telegram_allow_from_json="$(printf '%s\n' "$telegram_users_values" | jq -R . | jq -s .)"
256
+ fi
257
+
170
258
  mkdir -p "$CONFIG_DIR" "$WORKSPACE_DIR" "$TOOLS_DIR"
171
259
  chown -R ubuntu:ubuntu "$CONFIG_ROOT" "/home/ubuntu/openclaw-${INSTANCE_ID}"
172
260
 
@@ -190,7 +278,7 @@ run_openclaw_cli() {
190
278
  --network host \
191
279
  -e HOME=/home/node \
192
280
  -e OPENCLAW_GATEWAY_TOKEN="$GATEWAY_TOKEN" \
193
- -e OPENCLAW_TELEGRAM_TOKEN="$TELEGRAM_TOKEN" \
281
+ -e OPENCLAW_TELEGRAM_TOKEN="${TELEGRAM_TOKEN:-}" \
194
282
  -e OPENCLAW_MODEL="$MODEL" \
195
283
  -e OPENCLAW_TELEGRAM_ALLOW_FROM_JSON="$telegram_allow_from_json" \
196
284
  -e OPENCLAW_SKILLS_JSON="$skills_json" \
@@ -206,18 +294,6 @@ run_openclaw_cli() {
206
294
  "$OPENCLAW_IMAGE" -se
207
295
  }
208
296
 
209
- skills_json="[]"
210
- IFS=',' read -r -a skills_arr <<< "${SKILLS:-}"
211
- if (( ${#skills_arr[@]} > 0 )); then
212
- skills_json="$(printf '%s\n' "${skills_arr[@]}" | sed '/^$/d' | jq -R . | jq -s .)"
213
- fi
214
-
215
- telegram_allow_from_json="[]"
216
- IFS=',' read -r -a users_arr <<< "${TELEGRAM_USERS:-}"
217
- if (( ${#users_arr[@]} > 0 )); then
218
- telegram_allow_from_json="$(printf '%s\n' "${users_arr[@]}" | sed '/^$/d' | jq -R . | jq -s .)"
219
- fi
220
-
221
297
  run_openclaw_cli <<'EOF'
222
298
  set -euo pipefail
223
299
  OPENCLAW='node /app/openclaw.mjs'
@@ -228,14 +304,28 @@ $OPENCLAW config set gateway.auth.token "$OPENCLAW_GATEWAY_TOKEN"
228
304
  $OPENCLAW config set gateway.tailscale.mode off
229
305
  $OPENCLAW config set agents.defaults.model.primary "$OPENCLAW_MODEL"
230
306
  $OPENCLAW config set agents.defaults.skipBootstrap false --json
307
+ $OPENCLAW config set skills.allowBundled "$OPENCLAW_SKILLS_JSON" --json
308
+ EOF
309
+
310
+ if [[ -n "${TELEGRAM_TOKEN:-}" ]]; then
311
+ run_openclaw_cli <<'EOF'
312
+ set -euo pipefail
313
+ OPENCLAW='node /app/openclaw.mjs'
231
314
  $OPENCLAW config set channels.telegram.enabled true --json
232
315
  $OPENCLAW config set channels.telegram.botToken "$OPENCLAW_TELEGRAM_TOKEN"
233
316
  $OPENCLAW config set channels.telegram.dmPolicy allowlist
234
317
  $OPENCLAW config set channels.telegram.groupPolicy disabled
235
318
  $OPENCLAW config set channels.telegram.allowFrom "$OPENCLAW_TELEGRAM_ALLOW_FROM_JSON" --json
236
319
  $OPENCLAW config set plugins.entries.telegram.enabled true --json
237
- $OPENCLAW config set skills.allowBundled "$OPENCLAW_SKILLS_JSON" --json
238
320
  EOF
321
+ else
322
+ run_openclaw_cli <<'EOF'
323
+ set -euo pipefail
324
+ OPENCLAW='node /app/openclaw.mjs'
325
+ $OPENCLAW config set channels.telegram.enabled false --json
326
+ $OPENCLAW config set plugins.entries.telegram.enabled false --json
327
+ EOF
328
+ fi
239
329
 
240
330
  if [[ "$MODEL" == minimax/* ]]; then
241
331
  OPENCLAW_MINIMAX_PROVIDER_JSON="$(jq -cn --arg api_key "${MINIMAX_API_KEY:-}" '
@@ -263,15 +353,33 @@ EOF
263
353
  fi
264
354
 
265
355
  if [[ "${SKIP_BROWSER_INSTALL:-false}" != "true" ]]; then
266
- docker run --rm \
356
+ docker run --rm -i \
267
357
  --network host \
358
+ -e HOME=/home/node \
268
359
  -e PLAYWRIGHT_BROWSERS_PATH=/home/node/clawd/tools/.playwright \
360
+ -e PLAYWRIGHT_FALLBACK_PACKAGE="$PLAYWRIGHT_FALLBACK_PACKAGE" \
269
361
  -v "$TOOLS_DIR:/home/node/clawd/tools" \
270
362
  --entrypoint /bin/bash \
271
- "$OPENCLAW_IMAGE" -lc "
272
- set -euo pipefail
273
- npx --yes playwright@latest install chromium
274
- "
363
+ "$OPENCLAW_IMAGE" -se <<'EOF'
364
+ set -euo pipefail
365
+
366
+ if playwright_cli="$(node <<'NODE'
367
+ const path = require("path");
368
+ try {
369
+ const pkg = require.resolve("playwright/package.json");
370
+ process.stdout.write(path.join(path.dirname(pkg), "cli.js"));
371
+ } catch {
372
+ process.exit(1);
373
+ }
374
+ NODE
375
+ )"; then
376
+ echo "Using Playwright from image: $playwright_cli"
377
+ node "$playwright_cli" install chromium
378
+ else
379
+ echo "Using fallback Playwright package: $PLAYWRIGHT_FALLBACK_PACKAGE"
380
+ npx --yes "$PLAYWRIGHT_FALLBACK_PACKAGE" install chromium
381
+ fi
382
+ EOF
275
383
 
276
384
  chrome_host_path="$(
277
385
  find "$TOOLS_DIR/.playwright" -type f \
@@ -319,7 +427,7 @@ Requires=docker.service
319
427
  [Service]
320
428
  Type=simple
321
429
  ExecStartPre=-/usr/bin/docker rm -f openclaw-$INSTANCE_ID
322
- ExecStart=/usr/bin/docker run --rm --name openclaw-$INSTANCE_ID --init --network host --env-file $ENV_FILE -v $CONFIG_DIR:/home/node/.openclaw -v $WORKSPACE_DIR:/home/node/.openclaw/workspace -v $TOOLS_DIR:/home/node/clawd/tools $OPENCLAW_IMAGE node dist/index.js gateway --bind lan --port 18789
430
+ ExecStart=/usr/bin/docker run --rm --name openclaw-$INSTANCE_ID --init --network host --env-file $ENV_FILE -e HOME=/home/node -v $CONFIG_DIR:/home/node/.openclaw -v $WORKSPACE_DIR:/home/node/.openclaw/workspace -v $TOOLS_DIR:/home/node/clawd/tools $OPENCLAW_IMAGE node dist/index.js gateway --bind lan --port 18789
323
431
  ExecStop=/usr/bin/docker stop openclaw-$INSTANCE_ID
324
432
  Restart=always
325
433
  RestartSec=5
@@ -329,6 +437,7 @@ WantedBy=multi-user.target
329
437
  EOF
330
438
 
331
439
  systemctl daemon-reload
332
- systemctl enable --now "$GUEST_SERVICE"
440
+ systemctl enable "$GUEST_SERVICE"
441
+ systemctl restart "$GUEST_SERVICE"
333
442
 
334
443
  echo "Guest provisioning complete for $INSTANCE_ID"