anurag008w commited on
Commit
351ac42
·
unverified ·
1 Parent(s): 9f89c0a

Revert "Enable ephemeral package installs: restricted sudo + startup replay for HF Spaces"

Browse files
Files changed (3) hide show
  1. Dockerfile +2 -11
  2. README.md +0 -44
  3. start.sh +12 -358
Dockerfile CHANGED
@@ -14,7 +14,6 @@ ARG OPENCLAW_VERSION=latest
14
  # Install system dependencies
15
  RUN apt-get update && apt-get install -y \
16
  git \
17
- sudo \
18
  ca-certificates \
19
  jq \
20
  curl \
@@ -45,17 +44,9 @@ RUN apt-get update && apt-get install -y \
45
  pip3 install --no-cache-dir --break-system-packages huggingface_hub && \
46
  rm -rf /var/lib/apt/lists/*
47
 
48
- # Reuse existing node user (UID 1000). Allow passwordless package-manager
49
- # commands only so runtime apt installs can be replayed after HF Space restarts
50
- # without granting unrestricted sudo access.
51
  RUN mkdir -p /home/node/app /home/node/.openclaw && \
52
- chown -R 1000:1000 /home/node && \
53
- printf '%s\n' \
54
- 'Cmnd_Alias HUGGINGCLAW_APT = /usr/bin/apt, /usr/bin/apt-get, /usr/bin/dpkg' \
55
- 'node ALL=(root) NOPASSWD: HUGGINGCLAW_APT' \
56
- > /etc/sudoers.d/huggingclaw-apt && \
57
- chmod 0440 /etc/sudoers.d/huggingclaw-apt && \
58
- visudo -cf /etc/sudoers.d/huggingclaw-apt
59
 
60
  # Copy pre-built OpenClaw (skips npm install entirely — much faster!)
61
  COPY --from=openclaw --chown=1000:1000 /app /home/node/.openclaw/openclaw-app
 
14
  # Install system dependencies
15
  RUN apt-get update && apt-get install -y \
16
  git \
 
17
  ca-certificates \
18
  jq \
19
  curl \
 
44
  pip3 install --no-cache-dir --break-system-packages huggingface_hub && \
45
  rm -rf /var/lib/apt/lists/*
46
 
47
+ # Reuse existing node user (UID 1000)
 
 
48
  RUN mkdir -p /home/node/app /home/node/.openclaw && \
49
+ chown -R 1000:1000 /home/node
 
 
 
 
 
 
50
 
51
  # Copy pre-built OpenClaw (skips npm install entirely — much faster!)
52
  COPY --from=openclaw --chown=1000:1000 /app /home/node/.openclaw/openclaw-app
README.md CHANGED
@@ -164,50 +164,6 @@ HuggingClaw automatically syncs your workspace (chats, settings, sessions) to a
164
  | `HF_TOKEN` | — | HF token with **Write** access |
165
  | `SYNC_INTERVAL` | `180` | Backup frequency in seconds |
166
 
167
- ## 📦 Ephemeral Package Re-install *(Optional)*
168
-
169
- Yes — you can use extra packages after a Space restart without storing package files. The easiest option is to remember **one variable**:
170
-
171
- | Variable | What to put in it |
172
- | :--- | :--- |
173
- | `HUGGINGCLAW_RUN` | Any bash commands you want to run on every startup |
174
-
175
- Example:
176
-
177
- ```bash
178
- HUGGINGCLAW_RUN="""
179
- set -e
180
- sudo apt-get update
181
- sudo apt-get install -y ffmpeg
182
- python3 -m pip install --user pandas requests
183
- npm install -g typescript
184
- """
185
- ```
186
-
187
- For very quote-heavy or strange scripts, put a base64 script in the same variable:
188
-
189
- ```bash
190
- # locally
191
- base64 -w0 setup.sh
192
-
193
- # HF Variable
194
- HUGGINGCLAW_RUN=base64:<paste-output-here>
195
- ```
196
-
197
- How it works:
198
-
199
- 1. `HUGGINGCLAW_RUN` is run as a full bash script on every boot before the OpenClaw gateway launches, so multi-line commands, `if`, loops, functions, and heredocs work. Long installs will delay gateway startup.
200
- 2. Startup scripts load the same HuggingClaw shell wrappers as the interactive shell, so `apt install ...`, `pip install ...`, `npm install -g ...`, and `openclaw plugins install ...` behave consistently.
201
- 3. If you install from the OpenClaw shell manually, HuggingClaw records only successful install commands in `/home/node/.openclaw/workspace/startup.sh` for replay. Failed or dummy commands are not saved by the wrapper.
202
- 4. Package files are not persisted; commands are replayed to reconstruct them after restart.
203
-
204
- Errors are always printed as `ERROR:` lines in Space logs. By default HuggingClaw logs the error and continues booting; set `HUGGINGCLAW_STARTUP_STRICT=true` if the Space should fail fast when any startup install command fails.
205
-
206
- Advanced/backward-compatible variables still work if you prefer package-specific fields: `HUGGINGCLAW_APT_PACKAGES`, `HUGGINGCLAW_PIP_PACKAGES`, `HUGGINGCLAW_NPM_PACKAGES`, `HUGGINGCLAW_OPENCLAW_PLUGINS`, `HUGGINGCLAW_STARTUP_COMMANDS`, `HUGGINGCLAW_STARTUP_COMMAND_1`...`100`, `HUGGINGCLAW_STARTUP_SCRIPT`, and `HUGGINGCLAW_STARTUP_SCRIPT_B64`.
207
-
208
- > [!IMPORTANT]
209
- > `sudo` is available for package-manager commands only (`apt`, `apt-get`, and `dpkg`). This is enough for `sudo apt-get update` and `sudo apt-get install -y ...`, but it is not unrestricted root access. Apt-installed packages still disappear on Space restart, so put them in `HUGGINGCLAW_RUN` or let the shell wrapper record the command in `startup.sh`.
210
-
211
  ## 💓 Staying Alive *(Recommended on Free HF Spaces)*
212
 
213
  Your Space will automatically be kept awake by a background Cloudflare Worker when you configure the `CLOUDFLARE_WORKERS_TOKEN` secret. The worker uses a cron trigger to regularly ping your Space's `/health` endpoint. The dashboard displays the current keep-alive worker status.
 
164
  | `HF_TOKEN` | — | HF token with **Write** access |
165
  | `SYNC_INTERVAL` | `180` | Backup frequency in seconds |
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  ## 💓 Staying Alive *(Recommended on Free HF Spaces)*
168
 
169
  Your Space will automatically be kept awake by a background Cloudflare Worker when you configure the `CLOUDFLARE_WORKERS_TOKEN` secret. The worker uses a cron trigger to regularly ping your Space's `/health` endpoint. The dashboard displays the current keep-alive worker status.
start.sh CHANGED
@@ -129,20 +129,9 @@ mkdir -p /home/node/.openclaw/credentials
129
  mkdir -p /home/node/.openclaw/memory
130
  mkdir -p /home/node/.openclaw/extensions
131
  mkdir -p /home/node/.openclaw/workspace
132
- mkdir -p /home/node/.local/bin /home/node/.local/lib /home/node/.npm-global
133
  chmod 700 /home/node/.openclaw
134
  chmod 700 /home/node/.openclaw/credentials
135
 
136
- # User-installed packages are intentionally ephemeral in the container. Keep
137
- # npm/pip installs in user-writable locations, make apt noninteractive,
138
- # and persist only a tiny replay script in the synced workspace so packages
139
- # are re-installed after restart.
140
- export NPM_CONFIG_PREFIX="${NPM_CONFIG_PREFIX:-/home/node/.local}"
141
- export npm_config_prefix="$NPM_CONFIG_PREFIX"
142
- export PYTHONUSERBASE="${PYTHONUSERBASE:-/home/node/.local}"
143
- export DEBIAN_FRONTEND="${DEBIAN_FRONTEND:-noninteractive}"
144
- STARTUP_FILE="/home/node/.openclaw/workspace/startup.sh"
145
-
146
  # ── Restore workspace/state from HF Dataset ──
147
  BACKUP_DATASET="${BACKUP_DATASET_NAME:-huggingclaw-backup}"
148
  if [ -n "${HF_TOKEN:-}" ]; then
@@ -548,167 +537,26 @@ if [ -n "${CLOUDFLARE_WORKERS_TOKEN:-}" ]; then
548
  fi
549
 
550
  # ── Write shell capture wrappers to .bashrc ──
551
- # The wrappers persist only install commands, not downloaded package files.
552
- # On the next boot the synced workspace/startup.sh replays those commands.
553
- if [ ! -f "$STARTUP_FILE" ]; then
554
- touch "$STARTUP_FILE"
555
- chmod +x "$STARTUP_FILE"
556
- echo "Created workspace/startup.sh"
557
- fi
558
  cat > /home/node/.bashrc << 'BASHRC'
559
- export PATH="/home/node/.local/bin:$PATH"
560
- export NPM_CONFIG_PREFIX="${NPM_CONFIG_PREFIX:-/home/node/.local}"
561
- export npm_config_prefix="$NPM_CONFIG_PREFIX"
562
- export PYTHONUSERBASE="${PYTHONUSERBASE:-/home/node/.local}"
563
- export DEBIAN_FRONTEND="${DEBIAN_FRONTEND:-noninteractive}"
564
  STARTUP_FILE="/home/node/.openclaw/workspace/startup.sh"
565
  _hc_append() {
566
  local line="$*"
567
- mkdir -p "$(dirname "$STARTUP_FILE")"
568
- touch "$STARTUP_FILE"
569
- chmod +x "$STARTUP_FILE" 2>/dev/null || true
570
  grep -qxF "$line" "$STARTUP_FILE" 2>/dev/null || echo "$line" >> "$STARTUP_FILE"
571
  }
572
- _hc_quote_args() {
573
- local quoted=()
574
- local arg
575
- for arg in "$@"; do
576
- printf -v arg '%q' "$arg"
577
- quoted+=("$arg")
578
- done
579
- printf '%s' "${quoted[*]}"
580
- }
581
- _hc_append_cmd() {
582
- local cmd="$1"
583
- shift
584
- local args
585
- args=$(_hc_quote_args "$@")
586
- if [ -n "$args" ]; then
587
- _hc_append "$cmd $args"
588
- else
589
- _hc_append "$cmd"
590
- fi
591
- }
592
- _hc_has_arg() {
593
- local needle="$1"
594
- shift
595
- local arg
596
- for arg in "$@"; do
597
- [ "$arg" = "$needle" ] && return 0
598
- done
599
- return 1
600
- }
601
- _hc_can_sudo_apt() {
602
- command -v sudo >/dev/null 2>&1 && sudo -n apt-get --version >/dev/null 2>&1
603
- }
604
- _hc_apt_install() {
605
- if [ "$(id -u)" -eq 0 ]; then
606
- command apt-get update && command apt-get install -y "$@"
607
- elif _hc_can_sudo_apt; then
608
- sudo apt-get update && sudo apt-get install -y "$@"
609
- else
610
- echo "Error: apt install needs root. Rebuild with the latest HuggingClaw image or add packages to Dockerfile." >&2
611
- return 1
612
- fi
613
- }
614
  apt-get() {
615
- case "${1:-}" in
616
- install)
617
- shift
618
- _hc_apt_install "$@"
619
- local rc=$?
620
- if [ $rc -eq 0 ]; then
621
- _hc_append_cmd "sudo apt-get update && sudo apt-get install -y" "$@"
622
- fi
623
- return $rc
624
- ;;
625
- update)
626
- if [ "$(id -u)" -eq 0 ]; then
627
- command apt-get "$@"
628
- elif _hc_can_sudo_apt; then
629
- sudo apt-get "$@"
630
- else
631
- command apt-get "$@"
632
- fi
633
- return $?
634
- ;;
635
- *)
636
- command apt-get "$@"
637
- return $?
638
- ;;
639
- esac
640
  }
641
  apt() {
642
- case "${1:-}" in
643
- install)
644
- shift
645
- _hc_apt_install "$@"
646
- local rc=$?
647
- if [ $rc -eq 0 ]; then
648
- _hc_append_cmd "sudo apt-get update && sudo apt-get install -y" "$@"
649
- fi
650
- return $rc
651
- ;;
652
- update)
653
- if [ "$(id -u)" -eq 0 ]; then
654
- command apt "$@"
655
- elif _hc_can_sudo_apt; then
656
- sudo apt "$@"
657
- else
658
- command apt "$@"
659
- fi
660
- return $?
661
- ;;
662
- *)
663
- command apt "$@"
664
- return $?
665
- ;;
666
- esac
667
- }
668
- pip() {
669
- if [ "${1:-}" = "install" ] && [ -z "${VIRTUAL_ENV:-}" ] && ! _hc_has_arg --user "$@" && ! _hc_has_arg --prefix "$@"; then
670
- command pip install --user "${@:2}"
671
- else
672
- command pip "$@"
673
- fi
674
- local rc=$?
675
- if [ $rc -eq 0 ] && [ "${1:-}" = "install" ]; then
676
- _hc_append_cmd "python3 -m pip install --user" "${@:2}"
677
- fi
678
- return $rc
679
- }
680
- pip3() {
681
- if [ "${1:-}" = "install" ] && [ -z "${VIRTUAL_ENV:-}" ] && ! _hc_has_arg --user "$@" && ! _hc_has_arg --prefix "$@"; then
682
- command pip3 install --user "${@:2}"
683
- else
684
- command pip3 "$@"
685
- fi
686
- local rc=$?
687
- if [ $rc -eq 0 ] && [ "${1:-}" = "install" ]; then
688
- _hc_append_cmd "python3 -m pip install --user" "${@:2}"
689
- fi
690
- return $rc
691
- }
692
- npm() {
693
- command npm "$@"
694
- local rc=$?
695
- if [ $rc -eq 0 ] && [ "${1:-}" = "install" ] && { [ "${2:-}" = "-g" ] || [ "${2:-}" = "--global" ]; }; then
696
- _hc_append_cmd "npm install -g" "${@:3}"
697
- fi
698
- return $rc
699
- }
700
- openclaw() {
701
- command openclaw "$@"
702
- local rc=$?
703
- if [ $rc -eq 0 ] && [ "${1:-}" = "plugins" ] && [ "${2:-}" = "install" ]; then
704
- _hc_append_cmd "openclaw plugins install" "${@:3}"
705
- fi
706
- return $rc
707
  }
 
 
 
 
708
  BASHRC
709
- cat > /home/node/.profile <<'PROFILE'
710
- [ -f ~/.bashrc ] && . ~/.bashrc
711
- PROFILE
712
  echo "Shell capture wrappers ready."
713
 
714
  # ── Re-install previously installed plugins ──
@@ -732,199 +580,6 @@ if [ -f "$EXISTING_CONFIG" ]; then
732
  fi
733
  fi
734
 
735
- # ── Startup command runner ──
736
- # Runs user-provided boot commands one by one so failures are visible in logs.
737
- # By default failures are logged and boot continues; set
738
- # HUGGINGCLAW_STARTUP_STRICT=true to fail the Space startup on any error.
739
- HC_STARTUP_FAILURES=0
740
- HC_STARTUP_STRICT_NORMALIZED=$(printf '%s' "${HUGGINGCLAW_STARTUP_STRICT:-false}" | tr '[:upper:]' '[:lower:]')
741
- hc_run_startup_command() {
742
- local source_label="$1"
743
- local command_text="$2"
744
- [ -n "$command_text" ] || return 0
745
-
746
- echo "[startup:${source_label}] $command_text"
747
- set +e
748
- bash -lc "$command_text"
749
- local rc=$?
750
- set -e
751
- if [ "$rc" -eq 0 ]; then
752
- echo "[startup:${source_label}] ok"
753
- return 0
754
- fi
755
-
756
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
757
- echo "ERROR: startup command failed (${source_label}, exit ${rc}): $command_text" >&2
758
- return "$rc"
759
- }
760
-
761
- hc_run_startup_script() {
762
- local source_label="$1"
763
- local script_text="$2"
764
- [ -n "$script_text" ] || return 0
765
-
766
- local script_file
767
- script_file=$(mktemp "/tmp/huggingclaw-startup-${source_label//[^A-Za-z0-9_.-]/_}.XXXXXX.sh")
768
- {
769
- # Load HuggingClaw's install wrappers for env-provided scripts too, so
770
- # `apt install`, `pip install`, `npm install -g`, and OpenClaw plugin
771
- # installs behave the same way as they do in the interactive shell.
772
- echo '[ -f /home/node/.bashrc ] && . /home/node/.bashrc'
773
- printf '%s\n' "$script_text"
774
- } > "$script_file"
775
- chmod 700 "$script_file"
776
-
777
- echo "[startup:${source_label}] running script (${script_file})"
778
- set +e
779
- bash "$script_file"
780
- local rc=$?
781
- set -e
782
- rm -f "$script_file"
783
-
784
- if [ "$rc" -eq 0 ]; then
785
- echo "[startup:${source_label}] ok"
786
- return 0
787
- fi
788
-
789
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
790
- echo "ERROR: startup script failed (${source_label}, exit ${rc})" >&2
791
- return "$rc"
792
- }
793
- hc_run_startup_script_b64() {
794
- local source_label="$1"
795
- local encoded_script="$2"
796
- [ -n "$encoded_script" ] || return 0
797
-
798
- local script_text
799
- if ! script_text=$(printf '%s' "$encoded_script" | base64 -d 2>/dev/null); then
800
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
801
- echo "ERROR: startup script base64 decode failed (${source_label})" >&2
802
- return 1
803
- fi
804
-
805
- hc_run_startup_script "$source_label" "$script_text"
806
- }
807
-
808
-
809
- hc_run_startup_auto() {
810
- local source_label="$1"
811
- local payload="$2"
812
- [ -n "$payload" ] || return 0
813
-
814
- if [[ "$payload" == base64:* ]]; then
815
- hc_run_startup_script_b64 "$source_label" "${payload#base64:}"
816
- elif [[ "$payload" == b64:* ]]; then
817
- hc_run_startup_script_b64 "$source_label" "${payload#b64:}"
818
- else
819
- hc_run_startup_script "$source_label" "$payload"
820
- fi
821
- }
822
-
823
- hc_run_command_block() {
824
- local source_label="$1"
825
- local command_block="$2"
826
- local line
827
- local index=0
828
-
829
- while IFS= read -r line || [ -n "$line" ]; do
830
- # Skip blank lines and comments so multi-line env vars can be documented.
831
- [[ "$line" =~ ^[[:space:]]*$ ]] && continue
832
- [[ "$line" =~ ^[[:space:]]*# ]] && continue
833
-
834
- index=$((index + 1))
835
- hc_run_startup_command "${source_label}[${index}]" "$line" || true
836
- done <<< "$command_block"
837
- }
838
- hc_finish_startup_commands() {
839
- if [ "$HC_STARTUP_FAILURES" -gt 0 ]; then
840
- echo "ERROR: ${HC_STARTUP_FAILURES} startup command(s) failed. Check the log lines above." >&2
841
- if [ "$HC_STARTUP_STRICT_NORMALIZED" = "true" ] || [ "$HC_STARTUP_STRICT_NORMALIZED" = "1" ] || [ "$HC_STARTUP_STRICT_NORMALIZED" = "yes" ]; then
842
- echo "ERROR: HUGGINGCLAW_STARTUP_STRICT=true, stopping startup." >&2
843
- exit 1
844
- fi
845
- fi
846
- return 0
847
- }
848
-
849
- # ── Optional package install lists from HF Variables/Secrets ──
850
- # These install package names every boot without persisting package files.
851
- # Use them when you prefer HF Variables over editing workspace/startup.sh.
852
- if [ -n "${HUGGINGCLAW_APT_PACKAGES:-}" ]; then
853
- echo "Installing apt packages from HUGGINGCLAW_APT_PACKAGES..."
854
- read -r -a HC_APT_PACKAGES <<< "$HUGGINGCLAW_APT_PACKAGES"
855
- if command -v sudo >/dev/null 2>&1; then
856
- if sudo apt-get update && sudo apt-get install -y "${HC_APT_PACKAGES[@]}"; then
857
- echo "HUGGINGCLAW_APT_PACKAGES install complete."
858
- else
859
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
860
- echo "ERROR: HUGGINGCLAW_APT_PACKAGES install failed: ${HUGGINGCLAW_APT_PACKAGES}" >&2
861
- fi
862
- else
863
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
864
- echo "ERROR: sudo is unavailable; HUGGINGCLAW_APT_PACKAGES install skipped" >&2
865
- fi
866
- fi
867
- if [ -n "${HUGGINGCLAW_PIP_PACKAGES:-}" ]; then
868
- echo "Installing Python packages from HUGGINGCLAW_PIP_PACKAGES..."
869
- read -r -a HC_PIP_PACKAGES <<< "$HUGGINGCLAW_PIP_PACKAGES"
870
- if python3 -m pip install --user "${HC_PIP_PACKAGES[@]}"; then
871
- echo "HUGGINGCLAW_PIP_PACKAGES install complete."
872
- else
873
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
874
- echo "ERROR: HUGGINGCLAW_PIP_PACKAGES install failed: ${HUGGINGCLAW_PIP_PACKAGES}" >&2
875
- fi
876
- fi
877
- if [ -n "${HUGGINGCLAW_NPM_PACKAGES:-}" ]; then
878
- echo "Installing global npm packages from HUGGINGCLAW_NPM_PACKAGES..."
879
- read -r -a HC_NPM_PACKAGES <<< "$HUGGINGCLAW_NPM_PACKAGES"
880
- if npm install -g "${HC_NPM_PACKAGES[@]}"; then
881
- echo "HUGGINGCLAW_NPM_PACKAGES install complete."
882
- else
883
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
884
- echo "ERROR: HUGGINGCLAW_NPM_PACKAGES install failed: ${HUGGINGCLAW_NPM_PACKAGES}" >&2
885
- fi
886
- fi
887
- if [ -n "${HUGGINGCLAW_OPENCLAW_PLUGINS:-}" ]; then
888
- echo "Installing OpenClaw plugins from HUGGINGCLAW_OPENCLAW_PLUGINS..."
889
- read -r -a HC_OPENCLAW_PLUGINS <<< "$HUGGINGCLAW_OPENCLAW_PLUGINS"
890
- if openclaw plugins install "${HC_OPENCLAW_PLUGINS[@]}"; then
891
- echo "HUGGINGCLAW_OPENCLAW_PLUGINS install complete."
892
- else
893
- HC_STARTUP_FAILURES=$((HC_STARTUP_FAILURES + 1))
894
- echo "ERROR: HUGGINGCLAW_OPENCLAW_PLUGINS install failed: ${HUGGINGCLAW_OPENCLAW_PLUGINS}" >&2
895
- fi
896
- fi
897
-
898
- # ── Arbitrary startup commands from HF Variables/Secrets ──
899
- # Recommended: use one variable, HUGGINGCLAW_RUN, as a full bash script. If the
900
- # value starts with base64: or b64:, the rest is decoded and run as the script.
901
- # Legacy granular HUGGINGCLAW_STARTUP_* variables are still supported below.
902
- if [ -n "${HUGGINGCLAW_RUN:-}" ]; then
903
- hc_run_startup_auto "HUGGINGCLAW_RUN" "$HUGGINGCLAW_RUN" || true
904
- fi
905
- if [ -n "${HUGGINGCLAW_STARTUP_COMMANDS:-}" ]; then
906
- echo "Running commands from HUGGINGCLAW_STARTUP_COMMANDS..."
907
- hc_run_command_block "HUGGINGCLAW_STARTUP_COMMANDS" "$HUGGINGCLAW_STARTUP_COMMANDS"
908
- fi
909
- for HC_STARTUP_INDEX in $(seq 1 100); do
910
- HC_STARTUP_VAR="HUGGINGCLAW_STARTUP_COMMAND_${HC_STARTUP_INDEX}"
911
- if [ -n "${!HC_STARTUP_VAR:-}" ]; then
912
- hc_run_startup_command "$HC_STARTUP_VAR" "${!HC_STARTUP_VAR}" || true
913
- fi
914
- done
915
- if [ -n "${HUGGINGCLAW_STARTUP_SCRIPT:-}" ]; then
916
- hc_run_startup_script "HUGGINGCLAW_STARTUP_SCRIPT" "$HUGGINGCLAW_STARTUP_SCRIPT" || true
917
- fi
918
- if [ -n "${HUGGINGCLAW_STARTUP_SCRIPT_B64:-}" ]; then
919
- hc_run_startup_script_b64 "HUGGINGCLAW_STARTUP_SCRIPT_B64" "$HUGGINGCLAW_STARTUP_SCRIPT_B64" || true
920
- fi
921
- for HC_STARTUP_INDEX in $(seq 1 20); do
922
- HC_STARTUP_VAR="HUGGINGCLAW_STARTUP_SCRIPT_B64_${HC_STARTUP_INDEX}"
923
- if [ -n "${!HC_STARTUP_VAR:-}" ]; then
924
- hc_run_startup_script_b64 "$HC_STARTUP_VAR" "${!HC_STARTUP_VAR}" || true
925
- fi
926
- done
927
-
928
  # ── Run workspace startup script ──
929
  STARTUP_FILE="/home/node/.openclaw/workspace/startup.sh"
930
  if [ ! -f "$STARTUP_FILE" ]; then
@@ -933,11 +588,10 @@ if [ ! -f "$STARTUP_FILE" ]; then
933
  echo "Created workspace/startup.sh"
934
  fi
935
  if [ -s "$STARTUP_FILE" ]; then
936
- echo "Running workspace/startup.sh script..."
937
- hc_run_startup_script "workspace/startup.sh" "$(cat "$STARTUP_FILE")" || true
938
- echo "Workspace startup script complete."
939
  fi
940
- hc_finish_startup_commands
941
 
942
  # ── Launch gateway ──
943
  echo "Launching OpenClaw gateway on port 7860..."
 
129
  mkdir -p /home/node/.openclaw/memory
130
  mkdir -p /home/node/.openclaw/extensions
131
  mkdir -p /home/node/.openclaw/workspace
 
132
  chmod 700 /home/node/.openclaw
133
  chmod 700 /home/node/.openclaw/credentials
134
 
 
 
 
 
 
 
 
 
 
 
135
  # ── Restore workspace/state from HF Dataset ──
136
  BACKUP_DATASET="${BACKUP_DATASET_NAME:-huggingclaw-backup}"
137
  if [ -n "${HF_TOKEN:-}" ]; then
 
537
  fi
538
 
539
  # ── Write shell capture wrappers to .bashrc ──
540
+ STARTUP_FILE="/home/node/.openclaw/workspace/startup.sh"
 
 
 
 
 
 
541
  cat > /home/node/.bashrc << 'BASHRC'
 
 
 
 
 
542
  STARTUP_FILE="/home/node/.openclaw/workspace/startup.sh"
543
  _hc_append() {
544
  local line="$*"
 
 
 
545
  grep -qxF "$line" "$STARTUP_FILE" 2>/dev/null || echo "$line" >> "$STARTUP_FILE"
546
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  apt-get() {
548
+ command apt-get "$@"
549
+ [[ "$1" == "install" ]] && _hc_append "apt-get install -y ${@:2}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
  }
551
  apt() {
552
+ command apt "$@"
553
+ [[ "$1" == "install" ]] && _hc_append "apt-get install -y ${@:2}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
  }
555
+ pip() { command pip "$@"; [[ "$1" == "install" ]] && _hc_append "pip install ${@:2}"; }
556
+ pip3() { command pip3 "$@"; [[ "$1" == "install" ]] && _hc_append "pip3 install ${@:2}"; }
557
+ npm() { command npm "$@"; [[ "$1" == "install" && "$2" == "-g" ]] && _hc_append "npm install -g ${@:3}"; }
558
+ openclaw() { command openclaw "$@"; [[ "$1" == "plugins" && "$2" == "install" ]] && _hc_append "openclaw plugins install ${@:3}"; }
559
  BASHRC
 
 
 
560
  echo "Shell capture wrappers ready."
561
 
562
  # ── Re-install previously installed plugins ──
 
580
  fi
581
  fi
582
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
  # ── Run workspace startup script ──
584
  STARTUP_FILE="/home/node/.openclaw/workspace/startup.sh"
585
  if [ ! -f "$STARTUP_FILE" ]; then
 
588
  echo "Created workspace/startup.sh"
589
  fi
590
  if [ -s "$STARTUP_FILE" ]; then
591
+ echo "Running workspace/startup.sh..."
592
+ bash "$STARTUP_FILE" || echo "Warning: startup.sh had errors, continuing..."
593
+ echo "Startup script complete."
594
  fi
 
595
 
596
  # ── Launch gateway ──
597
  echo "Launching OpenClaw gateway on port 7860..."